diff --git a/Makefile b/Makefile index 5e0869a4a0b..9bf15038f28 100644 --- a/Makefile +++ b/Makefile @@ -20,16 +20,20 @@ GOPKG = github.com/$(REPO)/$(NAME) TAG = $(eval TAG := $(shell date -u +%Y%m%d-%H%M%S))$(TAG) BASE_IMAGE = $(NAME)-base AGENT_IMAGE = $(NAME)-agent-ngt -GATEWAY_IMAGE = $(NAME)-gateway +BACKUP_GATEWAY_IMAGE = $(NAME)-backup-gateway +CI_CONTAINER_IMAGE = $(NAME)-ci-container DISCOVERER_IMAGE = $(NAME)-discoverer-k8s -META_REDIS_IMAGE = $(NAME)-meta-redis -META_CASSANDRA_IMAGE = $(NAME)-meta-cassandra -MANAGER_BACKUP_MYSQL_IMAGE = $(NAME)-manager-backup-mysql +FILTER_GATEWAY_IMAGE = $(NAME)-filter-gateway +GATEWAY_IMAGE = $(NAME)-gateway +HELM_OPERATOR_IMAGE = $(NAME)-helm-operator +LB_GATEWAY_IMAGE = $(NAME)-lb-gateway MANAGER_BACKUP_CASSANDRA_IMAGE = $(NAME)-manager-backup-cassandra +MANAGER_BACKUP_MYSQL_IMAGE = $(NAME)-manager-backup-mysql MANAGER_COMPRESSOR_IMAGE = $(NAME)-manager-compressor MANAGER_INDEX_IMAGE = $(NAME)-manager-index -CI_CONTAINER_IMAGE = $(NAME)-ci-container -HELM_OPERATOR_IMAGE = $(NAME)-helm-operator +META_CASSANDRA_IMAGE = $(NAME)-meta-cassandra +META_GATEWAY_IMAGE = $(NAME)-meta-gateway +META_REDIS_IMAGE = $(NAME)-meta-redis NGT_VERSION := $(eval NGT_VERSION := $(shell cat versions/NGT_VERSION))$(NGT_VERSION) NGT_REPO = github.com/yahoojapan/NGT diff --git a/Makefile.d/docker.mk b/Makefile.d/docker.mk index 2d9517b3c3e..9bc95ecb6d3 100644 --- a/Makefile.d/docker.mk +++ b/Makefile.d/docker.mk @@ -64,6 +64,42 @@ docker/name/gateway-vald: docker/build/gateway-vald: docker/build/base docker build -f dockers/gateway/vald/Dockerfile -t $(REPO)/$(GATEWAY_IMAGE) . +.PHONY: docker/name/gateway-meta +docker/name/gateway-meta: + @echo "$(REPO)/$(META_GATEWAY_IMAGE)" + +.PHONY: docker/build/gateway-meta +## build gateway-meta image +docker/build/gateway-meta: docker/build/base + docker build -f dockers/gateway/vald/Dockerfile -t $(REPO)/$(META_GATEWAY_IMAGE) . + +.PHONY: docker/name/gateway-backup +docker/name/gateway-backup: + @echo "$(REPO)/$(BACKUP_GATEWAY_IMAGE)" + +.PHONY: docker/build/gateway-backup +## build gateway-backup image +docker/build/gateway-backup: docker/build/base + docker build -f dockers/gateway/vald/Dockerfile -t $(REPO)/$(BACKUP_GATEWAY_IMAGE) . + +.PHONY: docker/name/gateway-filter +docker/name/gateway-filter: + @echo "$(REPO)/$(FILTER_GATEWAY_IMAGE)" + +.PHONY: docker/build/gateway-filter +## build gateway-filter image +docker/build/gateway-filter: docker/build/base + docker build -f dockers/gateway/vald/Dockerfile -t $(REPO)/$(FILTER_GATEWAY_IMAGE) . + +.PHONY: docker/name/gateway-lb +docker/name/gateway-lb: + @echo "$(REPO)/$(LB_GATEWAY_IMAGE)" + +.PHONY: docker/build/gateway-lb +## build gateway-lb image +docker/build/gateway-lb: docker/build/base + docker build -f dockers/gateway/vald/Dockerfile -t $(REPO)/$(LB_GATEWAY_IMAGE) . + .PHONY: docker/name/meta-redis docker/name/meta-redis: @echo "$(REPO)/$(META_REDIS_IMAGE)" diff --git a/apis/docs/filter/ingress/docs.md b/apis/docs/filter/ingress/docs.md index ca3624b91ac..1d811077e8a 100644 --- a/apis/docs/filter/ingress/docs.md +++ b/apis/docs/filter/ingress/docs.md @@ -30,6 +30,10 @@ | Method Name | Request Type | Response Type | Description | | ----------- | ------------ | ------------- | ------------| +| GenVector | [.payload.Object.Blob](#payload.Object.Blob) | [.payload.Object.Vector](#payload.Object.Vector) | | +| StreamGenVector | [.payload.Object.Blob](#payload.Object.Blob) stream | [.payload.Object.Vector](#payload.Object.Vector) stream | | +| FilterVector | [.payload.Object.Vector](#payload.Object.Vector) | [.payload.Object.Vector](#payload.Object.Vector) | | +| StreamFilterVector | [.payload.Object.Vector](#payload.Object.Vector) stream | [.payload.Object.Vector](#payload.Object.Vector) stream | | diff --git a/apis/docs/gateway/filter/docs.md b/apis/docs/gateway/filter/docs.md new file mode 100644 index 00000000000..c0c006fb807 --- /dev/null +++ b/apis/docs/gateway/filter/docs.md @@ -0,0 +1,68 @@ +# Protocol Documentation + + +## Table of Contents + +- [filter/filter.proto](#filter/filter.proto) + - [Filter](#filter.Filter) + +- [Scalar Value Types](#scalar-value-types) + + + + +

Top

+ +## filter/filter.proto + + + + + + + + + + + +### Filter + + +| Method Name | Request Type | Response Type | Description | +| ----------- | ------------ | ------------- | ------------| +| SearchObject | [.payload.Search.ObjectRequest](#payload.Search.ObjectRequest) | [.payload.Search.Response](#payload.Search.Response) | | +| StreamSearch | [.payload.Search.ObjectRequest](#payload.Search.ObjectRequest) stream | [.payload.Search.Response](#payload.Search.Response) stream | | +| InsertObject | [.payload.Object.Blob](#payload.Object.Blob) | [.payload.Empty](#payload.Empty) | | +| StreamInsertObject | [.payload.Object.Blob](#payload.Object.Blob) stream | [.payload.Empty](#payload.Empty) stream | | +| MultiInsertObject | [.payload.Object.Blob](#payload.Object.Blob) | [.payload.Empty](#payload.Empty) | | +| UpdateObject | [.payload.Object.Blob](#payload.Object.Blob) | [.payload.Empty](#payload.Empty) | | +| StreamUpdateObject | [.payload.Object.Blob](#payload.Object.Blob) stream | [.payload.Empty](#payload.Empty) stream | | +| MultiUpdateObject | [.payload.Object.Blob](#payload.Object.Blob) | [.payload.Empty](#payload.Empty) | | +| UpsertObject | [.payload.Object.Blob](#payload.Object.Blob) | [.payload.Empty](#payload.Empty) | | +| StreamUpsertObject | [.payload.Object.Blob](#payload.Object.Blob) stream | [.payload.Empty](#payload.Empty) stream | | +| MultiUpsertObject | [.payload.Object.Blob](#payload.Object.Blob) | [.payload.Empty](#payload.Empty) | | + + + + + +## Scalar Value Types + +| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby | +| ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- | +| double | | double | double | float | float64 | double | float | Float | +| float | | float | float | float | float32 | float | float | Float | +| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) | +| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum | +| uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) | +| uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) | +| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) | +| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum | +| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) | +| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum | +| sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) | +| sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum | +| bool | | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass | +| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) | +| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) | + diff --git a/apis/docs/payload/docs.md b/apis/docs/payload/docs.md index 0add23b3a23..b1ea0ab91d6 100644 --- a/apis/docs/payload/docs.md +++ b/apis/docs/payload/docs.md @@ -49,6 +49,7 @@ - [Meta.Val](#payload.Meta.Val) - [Meta.Vals](#payload.Meta.Vals) - [Object](#payload.Object) + - [Object.Blob](#payload.Object.Blob) - [Object.Distance](#payload.Object.Distance) - [Object.ID](#payload.Object.ID) - [Object.IDs](#payload.Object.IDs) @@ -61,6 +62,7 @@ - [Search](#payload.Search) - [Search.Config](#payload.Search.Config) - [Search.IDRequest](#payload.Search.IDRequest) + - [Search.ObjectRequest](#payload.Search.ObjectRequest) - [Search.Request](#payload.Search.Request) - [Search.Response](#payload.Search.Response) @@ -697,6 +699,22 @@ + + +### Object.Blob + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| id | [string](#string) | | | +| object | [bytes](#bytes) | | | + + + + + + ### Object.Distance @@ -876,6 +894,22 @@ + + +### Search.ObjectRequest + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| object | [bytes](#bytes) | | | +| config | [Search.Config](#payload.Search.Config) | | | + + + + + + ### Search.Request diff --git a/apis/grpc/filter/ingress/ingress_filter.pb.go b/apis/grpc/filter/ingress/ingress_filter.pb.go index 61734d018eb..6489b8874ec 100644 --- a/apis/grpc/filter/ingress/ingress_filter.pb.go +++ b/apis/grpc/filter/ingress/ingress_filter.pb.go @@ -23,9 +23,11 @@ import ( _ "github.com/danielvladco/go-proto-gql/pb" proto "github.com/gogo/protobuf/proto" - _ "github.com/vdaas/vald/apis/grpc/payload" + payload "github.com/vdaas/vald/apis/grpc/payload" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" ) // Reference imports to suppress errors if they are not otherwise used. @@ -42,19 +44,26 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package func init() { proto.RegisterFile("ingress/ingress_filter.proto", fileDescriptor_8f5342c46835d3ee) } var fileDescriptor_8f5342c46835d3ee = []byte{ - // 192 bytes of a gzipped FileDescriptorProto + // 299 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xc9, 0xcc, 0x4b, 0x2f, 0x4a, 0x2d, 0x2e, 0xd6, 0x87, 0xd2, 0xf1, 0x69, 0x99, 0x39, 0x25, 0xa9, 0x45, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x7c, 0xa8, 0xa2, 0x52, 0xbc, 0x05, 0x89, 0x95, 0x39, 0xf9, 0x89, 0x29, 0x10, 0x69, 0x29, 0x99, 0xf4, 0xfc, 0xfc, 0xf4, 0x9c, 0x54, 0xfd, 0xc4, 0x82, 0x4c, 0xfd, 0xc4, 0xbc, 0xbc, 0xfc, 0x92, 0xc4, 0x92, 0xcc, 0xfc, 0xbc, 0x62, 0xa8, 0x2c, 0x4f, 0x41, 0x92, 0x7e, - 0x7a, 0x61, 0x0e, 0x84, 0x67, 0xc4, 0xcf, 0xc5, 0xeb, 0x09, 0x31, 0xcc, 0x0d, 0x6c, 0x96, 0x53, - 0xc1, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0xc8, 0x25, 0x9b, - 0x5f, 0x94, 0xae, 0x57, 0x96, 0x92, 0x98, 0x58, 0xac, 0x57, 0x96, 0x98, 0x93, 0xa2, 0x07, 0x75, - 0x06, 0xd4, 0x7e, 0x27, 0xc1, 0xb0, 0xc4, 0x9c, 0x14, 0x14, 0xfd, 0x01, 0x8c, 0x51, 0x7a, 0xe9, - 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x60, 0xad, 0xfa, 0x20, 0xad, 0x20, - 0xd7, 0x14, 0xeb, 0xa7, 0x17, 0x15, 0x24, 0xeb, 0x43, 0x0c, 0x81, 0x79, 0x2d, 0x89, 0x0d, 0xec, - 0x12, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x72, 0x78, 0xf1, 0xa6, 0xf4, 0x00, 0x00, 0x00, + 0x7a, 0x61, 0x0e, 0x84, 0x67, 0x74, 0x92, 0x89, 0x8b, 0xd7, 0x13, 0x62, 0x9a, 0x1b, 0xd8, 0x30, + 0x21, 0x5f, 0x2e, 0x4e, 0xf7, 0xd4, 0xbc, 0xb0, 0xd4, 0xe4, 0x92, 0xfc, 0x22, 0x21, 0x11, 0x3d, + 0x98, 0xd1, 0xfe, 0x49, 0x59, 0xa9, 0xc9, 0x25, 0x7a, 0x4e, 0x39, 0xf9, 0x49, 0x52, 0x62, 0xe8, + 0xa2, 0x10, 0xd5, 0x4a, 0x42, 0x4d, 0x97, 0x9f, 0x4c, 0x66, 0xe2, 0x51, 0x62, 0xd7, 0xcf, 0x07, + 0x8b, 0x5b, 0x31, 0x6a, 0x09, 0xb9, 0x72, 0xf1, 0x07, 0x97, 0x14, 0xa5, 0x26, 0xe6, 0x92, 0x6b, + 0x28, 0x83, 0x06, 0xa3, 0x01, 0xa3, 0x50, 0x18, 0x17, 0x0f, 0xc4, 0x7d, 0x50, 0x33, 0x70, 0xa8, + 0xc6, 0x69, 0x8a, 0xd8, 0x86, 0x07, 0xf2, 0x8c, 0x70, 0xe7, 0x95, 0x81, 0x05, 0x41, 0xce, 0xf3, + 0xe2, 0x12, 0x82, 0x38, 0x8f, 0x22, 0xd3, 0xc1, 0x6e, 0x74, 0x2a, 0x38, 0xf1, 0x48, 0x8e, 0xf1, + 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0xb9, 0x64, 0xf3, 0x8b, 0xd2, 0xf5, 0xca, 0x52, + 0x12, 0x13, 0x8b, 0xf5, 0xca, 0x12, 0x73, 0x52, 0xf4, 0xa0, 0x31, 0x08, 0x8d, 0x3a, 0x27, 0xc1, + 0xb0, 0xc4, 0x9c, 0x14, 0x94, 0x90, 0x0f, 0x60, 0x8c, 0xd2, 0x4b, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, + 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x07, 0x6b, 0xd5, 0x07, 0x69, 0x05, 0x45, 0x64, 0xb1, 0x7e, 0x7a, + 0x51, 0x41, 0xb2, 0x3e, 0xc4, 0x10, 0x58, 0xaa, 0x48, 0x62, 0x03, 0x47, 0xa2, 0x31, 0x20, 0x00, + 0x00, 0xff, 0xff, 0xed, 0xb1, 0xae, 0xad, 0x2f, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -69,6 +78,10 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type IngressFilterClient interface { + GenVector(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Object_Vector, error) + StreamGenVector(ctx context.Context, opts ...grpc.CallOption) (IngressFilter_StreamGenVectorClient, error) + FilterVector(ctx context.Context, in *payload.Object_Vector, opts ...grpc.CallOption) (*payload.Object_Vector, error) + StreamFilterVector(ctx context.Context, opts ...grpc.CallOption) (IngressFilter_StreamFilterVectorClient, error) } type ingressFilterClient struct { @@ -79,22 +92,229 @@ func NewIngressFilterClient(cc *grpc.ClientConn) IngressFilterClient { return &ingressFilterClient{cc} } +func (c *ingressFilterClient) GenVector(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Object_Vector, error) { + out := new(payload.Object_Vector) + err := c.cc.Invoke(ctx, "/ingress_filter.IngressFilter/GenVector", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *ingressFilterClient) StreamGenVector(ctx context.Context, opts ...grpc.CallOption) (IngressFilter_StreamGenVectorClient, error) { + stream, err := c.cc.NewStream(ctx, &_IngressFilter_serviceDesc.Streams[0], "/ingress_filter.IngressFilter/StreamGenVector", opts...) + if err != nil { + return nil, err + } + x := &ingressFilterStreamGenVectorClient{stream} + return x, nil +} + +type IngressFilter_StreamGenVectorClient interface { + Send(*payload.Object_Blob) error + Recv() (*payload.Object_Vector, error) + grpc.ClientStream +} + +type ingressFilterStreamGenVectorClient struct { + grpc.ClientStream +} + +func (x *ingressFilterStreamGenVectorClient) Send(m *payload.Object_Blob) error { + return x.ClientStream.SendMsg(m) +} + +func (x *ingressFilterStreamGenVectorClient) Recv() (*payload.Object_Vector, error) { + m := new(payload.Object_Vector) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *ingressFilterClient) FilterVector(ctx context.Context, in *payload.Object_Vector, opts ...grpc.CallOption) (*payload.Object_Vector, error) { + out := new(payload.Object_Vector) + err := c.cc.Invoke(ctx, "/ingress_filter.IngressFilter/FilterVector", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *ingressFilterClient) StreamFilterVector(ctx context.Context, opts ...grpc.CallOption) (IngressFilter_StreamFilterVectorClient, error) { + stream, err := c.cc.NewStream(ctx, &_IngressFilter_serviceDesc.Streams[1], "/ingress_filter.IngressFilter/StreamFilterVector", opts...) + if err != nil { + return nil, err + } + x := &ingressFilterStreamFilterVectorClient{stream} + return x, nil +} + +type IngressFilter_StreamFilterVectorClient interface { + Send(*payload.Object_Vector) error + Recv() (*payload.Object_Vector, error) + grpc.ClientStream +} + +type ingressFilterStreamFilterVectorClient struct { + grpc.ClientStream +} + +func (x *ingressFilterStreamFilterVectorClient) Send(m *payload.Object_Vector) error { + return x.ClientStream.SendMsg(m) +} + +func (x *ingressFilterStreamFilterVectorClient) Recv() (*payload.Object_Vector, error) { + m := new(payload.Object_Vector) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + // IngressFilterServer is the server API for IngressFilter service. type IngressFilterServer interface { + GenVector(context.Context, *payload.Object_Blob) (*payload.Object_Vector, error) + StreamGenVector(IngressFilter_StreamGenVectorServer) error + FilterVector(context.Context, *payload.Object_Vector) (*payload.Object_Vector, error) + StreamFilterVector(IngressFilter_StreamFilterVectorServer) error } // UnimplementedIngressFilterServer can be embedded to have forward compatible implementations. type UnimplementedIngressFilterServer struct { } +func (*UnimplementedIngressFilterServer) GenVector(ctx context.Context, req *payload.Object_Blob) (*payload.Object_Vector, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenVector not implemented") +} +func (*UnimplementedIngressFilterServer) StreamGenVector(srv IngressFilter_StreamGenVectorServer) error { + return status.Errorf(codes.Unimplemented, "method StreamGenVector not implemented") +} +func (*UnimplementedIngressFilterServer) FilterVector(ctx context.Context, req *payload.Object_Vector) (*payload.Object_Vector, error) { + return nil, status.Errorf(codes.Unimplemented, "method FilterVector not implemented") +} +func (*UnimplementedIngressFilterServer) StreamFilterVector(srv IngressFilter_StreamFilterVectorServer) error { + return status.Errorf(codes.Unimplemented, "method StreamFilterVector not implemented") +} + func RegisterIngressFilterServer(s *grpc.Server, srv IngressFilterServer) { s.RegisterService(&_IngressFilter_serviceDesc, srv) } +func _IngressFilter_GenVector_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(payload.Object_Blob) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IngressFilterServer).GenVector(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ingress_filter.IngressFilter/GenVector", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IngressFilterServer).GenVector(ctx, req.(*payload.Object_Blob)) + } + return interceptor(ctx, in, info, handler) +} + +func _IngressFilter_StreamGenVector_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(IngressFilterServer).StreamGenVector(&ingressFilterStreamGenVectorServer{stream}) +} + +type IngressFilter_StreamGenVectorServer interface { + Send(*payload.Object_Vector) error + Recv() (*payload.Object_Blob, error) + grpc.ServerStream +} + +type ingressFilterStreamGenVectorServer struct { + grpc.ServerStream +} + +func (x *ingressFilterStreamGenVectorServer) Send(m *payload.Object_Vector) error { + return x.ServerStream.SendMsg(m) +} + +func (x *ingressFilterStreamGenVectorServer) Recv() (*payload.Object_Blob, error) { + m := new(payload.Object_Blob) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _IngressFilter_FilterVector_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(payload.Object_Vector) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IngressFilterServer).FilterVector(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ingress_filter.IngressFilter/FilterVector", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IngressFilterServer).FilterVector(ctx, req.(*payload.Object_Vector)) + } + return interceptor(ctx, in, info, handler) +} + +func _IngressFilter_StreamFilterVector_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(IngressFilterServer).StreamFilterVector(&ingressFilterStreamFilterVectorServer{stream}) +} + +type IngressFilter_StreamFilterVectorServer interface { + Send(*payload.Object_Vector) error + Recv() (*payload.Object_Vector, error) + grpc.ServerStream +} + +type ingressFilterStreamFilterVectorServer struct { + grpc.ServerStream +} + +func (x *ingressFilterStreamFilterVectorServer) Send(m *payload.Object_Vector) error { + return x.ServerStream.SendMsg(m) +} + +func (x *ingressFilterStreamFilterVectorServer) Recv() (*payload.Object_Vector, error) { + m := new(payload.Object_Vector) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + var _IngressFilter_serviceDesc = grpc.ServiceDesc{ ServiceName: "ingress_filter.IngressFilter", HandlerType: (*IngressFilterServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{}, - Metadata: "ingress/ingress_filter.proto", + Methods: []grpc.MethodDesc{ + { + MethodName: "GenVector", + Handler: _IngressFilter_GenVector_Handler, + }, + { + MethodName: "FilterVector", + Handler: _IngressFilter_FilterVector_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "StreamGenVector", + Handler: _IngressFilter_StreamGenVector_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "StreamFilterVector", + Handler: _IngressFilter_StreamFilterVector_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "ingress/ingress_filter.proto", } diff --git a/apis/grpc/gateway/filter/filter.pb.go b/apis/grpc/gateway/filter/filter.pb.go new file mode 100644 index 00000000000..fd64999ef9e --- /dev/null +++ b/apis/grpc/gateway/filter/filter.pb.go @@ -0,0 +1,641 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package filter + +import ( + context "context" + fmt "fmt" + math "math" + + _ "github.com/danielvladco/go-proto-gql/pb" + proto "github.com/gogo/protobuf/proto" + payload "github.com/vdaas/vald/apis/grpc/payload" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +func init() { proto.RegisterFile("filter/filter.proto", fileDescriptor_f45b4a1fb0c46f6e) } + +var fileDescriptor_f45b4a1fb0c46f6e = []byte{ + // 374 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x93, 0xb1, 0x4e, 0xf3, 0x30, + 0x14, 0x85, 0x7f, 0xff, 0x43, 0x06, 0x2b, 0x54, 0x6a, 0xca, 0x00, 0x11, 0x2d, 0x52, 0x27, 0xc4, + 0x60, 0x23, 0xd8, 0x60, 0x41, 0x95, 0x00, 0x31, 0x54, 0xa0, 0x56, 0x30, 0xb0, 0xdd, 0x24, 0x26, + 0x0d, 0x72, 0x63, 0x37, 0x76, 0x8a, 0xba, 0xf2, 0x0a, 0xbc, 0x08, 0x1b, 0xaf, 0xc0, 0x88, 0xc4, + 0x0b, 0x54, 0x15, 0x0f, 0x82, 0x9a, 0x1b, 0x2a, 0xa8, 0x60, 0x20, 0x9d, 0x22, 0x9f, 0x9b, 0xfb, + 0xf9, 0x1c, 0x59, 0x87, 0x36, 0x6e, 0x13, 0x69, 0x45, 0xc6, 0xf1, 0xc3, 0x74, 0xa6, 0xac, 0xf2, + 0x1c, 0x3c, 0xf9, 0x6b, 0x1a, 0x26, 0x52, 0x41, 0x84, 0xb2, 0xbf, 0x15, 0x2b, 0x15, 0x4b, 0xc1, + 0x41, 0x27, 0x1c, 0xd2, 0x54, 0x59, 0xb0, 0x89, 0x4a, 0x4d, 0x39, 0x75, 0x75, 0xc0, 0xe3, 0x91, + 0xc4, 0xd3, 0xfe, 0xb3, 0x43, 0x9d, 0xd3, 0x82, 0xe2, 0x05, 0xd4, 0xed, 0x0b, 0xc8, 0xc2, 0xc1, + 0x45, 0x70, 0x27, 0x42, 0xeb, 0x35, 0xd9, 0x27, 0x16, 0x65, 0x86, 0x7a, 0x4f, 0x8c, 0x72, 0x61, + 0xac, 0xbf, 0xb1, 0x3c, 0xee, 0x09, 0xa3, 0x55, 0x6a, 0x44, 0x7b, 0xf3, 0xe1, 0xed, 0xfd, 0xf1, + 0x7f, 0xa3, 0x5d, 0xe3, 0xa6, 0x98, 0x70, 0x55, 0x2c, 0x1e, 0x92, 0x5d, 0xaf, 0x4b, 0xdd, 0xbe, + 0xcd, 0x04, 0x0c, 0x71, 0xa7, 0xfa, 0x1d, 0xff, 0x76, 0xc8, 0x1e, 0xf1, 0xfa, 0xd4, 0x3d, 0x4f, + 0x8d, 0xc8, 0x6c, 0x69, 0x79, 0x7d, 0xf1, 0x3f, 0x0a, 0xac, 0x23, 0x55, 0xe0, 0xd7, 0x16, 0xea, + 0xc9, 0x50, 0xdb, 0x49, 0xbb, 0xf9, 0x34, 0xdd, 0x26, 0x0b, 0x8f, 0x49, 0x01, 0xf8, 0xe2, 0xf1, + 0x98, 0x7a, 0xe8, 0xb1, 0x02, 0x1a, 0x6d, 0x1d, 0xd1, 0x7a, 0x37, 0x97, 0x36, 0xa9, 0x02, 0x98, + 0x67, 0xba, 0xd2, 0x11, 0x58, 0xb1, 0x42, 0xa6, 0xbc, 0x00, 0xfc, 0x94, 0xa9, 0x02, 0xfa, 0x7b, + 0xa6, 0x2a, 0x00, 0xcc, 0xb4, 0xe2, 0x3b, 0xe5, 0xfa, 0xb7, 0x77, 0xaa, 0x80, 0x5e, 0xce, 0xf4, + 0x77, 0x40, 0x47, 0xbf, 0xcc, 0x5a, 0xe4, 0x75, 0xd6, 0x22, 0xd3, 0x59, 0x8b, 0xd0, 0xa6, 0xca, + 0x62, 0x36, 0x8e, 0x00, 0x0c, 0x1b, 0x83, 0x8c, 0x58, 0x0c, 0x56, 0xdc, 0xc3, 0x84, 0x61, 0x43, + 0x3b, 0xf5, 0x6b, 0x90, 0x11, 0xf6, 0xec, 0x0c, 0x27, 0x97, 0xe4, 0x86, 0xc5, 0x89, 0x1d, 0xe4, + 0x01, 0x0b, 0xd5, 0x90, 0x17, 0xab, 0x7c, 0xbe, 0x3a, 0xaf, 0xad, 0xe1, 0x71, 0xa6, 0x43, 0x5e, + 0x42, 0xca, 0xd2, 0x07, 0x4e, 0x51, 0xd9, 0x83, 0x8f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2c, 0xf0, + 0xcb, 0xd3, 0x0c, 0x04, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// FilterClient is the client API for Filter service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type FilterClient interface { + SearchObject(ctx context.Context, in *payload.Search_ObjectRequest, opts ...grpc.CallOption) (*payload.Search_Response, error) + StreamSearch(ctx context.Context, opts ...grpc.CallOption) (Filter_StreamSearchClient, error) + InsertObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) + StreamInsertObject(ctx context.Context, opts ...grpc.CallOption) (Filter_StreamInsertObjectClient, error) + MultiInsertObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) + UpdateObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) + StreamUpdateObject(ctx context.Context, opts ...grpc.CallOption) (Filter_StreamUpdateObjectClient, error) + MultiUpdateObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) + UpsertObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) + StreamUpsertObject(ctx context.Context, opts ...grpc.CallOption) (Filter_StreamUpsertObjectClient, error) + MultiUpsertObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) +} + +type filterClient struct { + cc *grpc.ClientConn +} + +func NewFilterClient(cc *grpc.ClientConn) FilterClient { + return &filterClient{cc} +} + +func (c *filterClient) SearchObject(ctx context.Context, in *payload.Search_ObjectRequest, opts ...grpc.CallOption) (*payload.Search_Response, error) { + out := new(payload.Search_Response) + err := c.cc.Invoke(ctx, "/filter.Filter/SearchObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *filterClient) StreamSearch(ctx context.Context, opts ...grpc.CallOption) (Filter_StreamSearchClient, error) { + stream, err := c.cc.NewStream(ctx, &_Filter_serviceDesc.Streams[0], "/filter.Filter/StreamSearch", opts...) + if err != nil { + return nil, err + } + x := &filterStreamSearchClient{stream} + return x, nil +} + +type Filter_StreamSearchClient interface { + Send(*payload.Search_ObjectRequest) error + Recv() (*payload.Search_Response, error) + grpc.ClientStream +} + +type filterStreamSearchClient struct { + grpc.ClientStream +} + +func (x *filterStreamSearchClient) Send(m *payload.Search_ObjectRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *filterStreamSearchClient) Recv() (*payload.Search_Response, error) { + m := new(payload.Search_Response) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *filterClient) InsertObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) { + out := new(payload.Empty) + err := c.cc.Invoke(ctx, "/filter.Filter/InsertObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *filterClient) StreamInsertObject(ctx context.Context, opts ...grpc.CallOption) (Filter_StreamInsertObjectClient, error) { + stream, err := c.cc.NewStream(ctx, &_Filter_serviceDesc.Streams[1], "/filter.Filter/StreamInsertObject", opts...) + if err != nil { + return nil, err + } + x := &filterStreamInsertObjectClient{stream} + return x, nil +} + +type Filter_StreamInsertObjectClient interface { + Send(*payload.Object_Blob) error + Recv() (*payload.Empty, error) + grpc.ClientStream +} + +type filterStreamInsertObjectClient struct { + grpc.ClientStream +} + +func (x *filterStreamInsertObjectClient) Send(m *payload.Object_Blob) error { + return x.ClientStream.SendMsg(m) +} + +func (x *filterStreamInsertObjectClient) Recv() (*payload.Empty, error) { + m := new(payload.Empty) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *filterClient) MultiInsertObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) { + out := new(payload.Empty) + err := c.cc.Invoke(ctx, "/filter.Filter/MultiInsertObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *filterClient) UpdateObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) { + out := new(payload.Empty) + err := c.cc.Invoke(ctx, "/filter.Filter/UpdateObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *filterClient) StreamUpdateObject(ctx context.Context, opts ...grpc.CallOption) (Filter_StreamUpdateObjectClient, error) { + stream, err := c.cc.NewStream(ctx, &_Filter_serviceDesc.Streams[2], "/filter.Filter/StreamUpdateObject", opts...) + if err != nil { + return nil, err + } + x := &filterStreamUpdateObjectClient{stream} + return x, nil +} + +type Filter_StreamUpdateObjectClient interface { + Send(*payload.Object_Blob) error + Recv() (*payload.Empty, error) + grpc.ClientStream +} + +type filterStreamUpdateObjectClient struct { + grpc.ClientStream +} + +func (x *filterStreamUpdateObjectClient) Send(m *payload.Object_Blob) error { + return x.ClientStream.SendMsg(m) +} + +func (x *filterStreamUpdateObjectClient) Recv() (*payload.Empty, error) { + m := new(payload.Empty) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *filterClient) MultiUpdateObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) { + out := new(payload.Empty) + err := c.cc.Invoke(ctx, "/filter.Filter/MultiUpdateObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *filterClient) UpsertObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) { + out := new(payload.Empty) + err := c.cc.Invoke(ctx, "/filter.Filter/UpsertObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *filterClient) StreamUpsertObject(ctx context.Context, opts ...grpc.CallOption) (Filter_StreamUpsertObjectClient, error) { + stream, err := c.cc.NewStream(ctx, &_Filter_serviceDesc.Streams[3], "/filter.Filter/StreamUpsertObject", opts...) + if err != nil { + return nil, err + } + x := &filterStreamUpsertObjectClient{stream} + return x, nil +} + +type Filter_StreamUpsertObjectClient interface { + Send(*payload.Object_Blob) error + Recv() (*payload.Empty, error) + grpc.ClientStream +} + +type filterStreamUpsertObjectClient struct { + grpc.ClientStream +} + +func (x *filterStreamUpsertObjectClient) Send(m *payload.Object_Blob) error { + return x.ClientStream.SendMsg(m) +} + +func (x *filterStreamUpsertObjectClient) Recv() (*payload.Empty, error) { + m := new(payload.Empty) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *filterClient) MultiUpsertObject(ctx context.Context, in *payload.Object_Blob, opts ...grpc.CallOption) (*payload.Empty, error) { + out := new(payload.Empty) + err := c.cc.Invoke(ctx, "/filter.Filter/MultiUpsertObject", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// FilterServer is the server API for Filter service. +type FilterServer interface { + SearchObject(context.Context, *payload.Search_ObjectRequest) (*payload.Search_Response, error) + StreamSearch(Filter_StreamSearchServer) error + InsertObject(context.Context, *payload.Object_Blob) (*payload.Empty, error) + StreamInsertObject(Filter_StreamInsertObjectServer) error + MultiInsertObject(context.Context, *payload.Object_Blob) (*payload.Empty, error) + UpdateObject(context.Context, *payload.Object_Blob) (*payload.Empty, error) + StreamUpdateObject(Filter_StreamUpdateObjectServer) error + MultiUpdateObject(context.Context, *payload.Object_Blob) (*payload.Empty, error) + UpsertObject(context.Context, *payload.Object_Blob) (*payload.Empty, error) + StreamUpsertObject(Filter_StreamUpsertObjectServer) error + MultiUpsertObject(context.Context, *payload.Object_Blob) (*payload.Empty, error) +} + +// UnimplementedFilterServer can be embedded to have forward compatible implementations. +type UnimplementedFilterServer struct { +} + +func (*UnimplementedFilterServer) SearchObject(ctx context.Context, req *payload.Search_ObjectRequest) (*payload.Search_Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchObject not implemented") +} +func (*UnimplementedFilterServer) StreamSearch(srv Filter_StreamSearchServer) error { + return status.Errorf(codes.Unimplemented, "method StreamSearch not implemented") +} +func (*UnimplementedFilterServer) InsertObject(ctx context.Context, req *payload.Object_Blob) (*payload.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method InsertObject not implemented") +} +func (*UnimplementedFilterServer) StreamInsertObject(srv Filter_StreamInsertObjectServer) error { + return status.Errorf(codes.Unimplemented, "method StreamInsertObject not implemented") +} +func (*UnimplementedFilterServer) MultiInsertObject(ctx context.Context, req *payload.Object_Blob) (*payload.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method MultiInsertObject not implemented") +} +func (*UnimplementedFilterServer) UpdateObject(ctx context.Context, req *payload.Object_Blob) (*payload.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateObject not implemented") +} +func (*UnimplementedFilterServer) StreamUpdateObject(srv Filter_StreamUpdateObjectServer) error { + return status.Errorf(codes.Unimplemented, "method StreamUpdateObject not implemented") +} +func (*UnimplementedFilterServer) MultiUpdateObject(ctx context.Context, req *payload.Object_Blob) (*payload.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method MultiUpdateObject not implemented") +} +func (*UnimplementedFilterServer) UpsertObject(ctx context.Context, req *payload.Object_Blob) (*payload.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpsertObject not implemented") +} +func (*UnimplementedFilterServer) StreamUpsertObject(srv Filter_StreamUpsertObjectServer) error { + return status.Errorf(codes.Unimplemented, "method StreamUpsertObject not implemented") +} +func (*UnimplementedFilterServer) MultiUpsertObject(ctx context.Context, req *payload.Object_Blob) (*payload.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method MultiUpsertObject not implemented") +} + +func RegisterFilterServer(s *grpc.Server, srv FilterServer) { + s.RegisterService(&_Filter_serviceDesc, srv) +} + +func _Filter_SearchObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(payload.Search_ObjectRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FilterServer).SearchObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/filter.Filter/SearchObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FilterServer).SearchObject(ctx, req.(*payload.Search_ObjectRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Filter_StreamSearch_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(FilterServer).StreamSearch(&filterStreamSearchServer{stream}) +} + +type Filter_StreamSearchServer interface { + Send(*payload.Search_Response) error + Recv() (*payload.Search_ObjectRequest, error) + grpc.ServerStream +} + +type filterStreamSearchServer struct { + grpc.ServerStream +} + +func (x *filterStreamSearchServer) Send(m *payload.Search_Response) error { + return x.ServerStream.SendMsg(m) +} + +func (x *filterStreamSearchServer) Recv() (*payload.Search_ObjectRequest, error) { + m := new(payload.Search_ObjectRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _Filter_InsertObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(payload.Object_Blob) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FilterServer).InsertObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/filter.Filter/InsertObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FilterServer).InsertObject(ctx, req.(*payload.Object_Blob)) + } + return interceptor(ctx, in, info, handler) +} + +func _Filter_StreamInsertObject_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(FilterServer).StreamInsertObject(&filterStreamInsertObjectServer{stream}) +} + +type Filter_StreamInsertObjectServer interface { + Send(*payload.Empty) error + Recv() (*payload.Object_Blob, error) + grpc.ServerStream +} + +type filterStreamInsertObjectServer struct { + grpc.ServerStream +} + +func (x *filterStreamInsertObjectServer) Send(m *payload.Empty) error { + return x.ServerStream.SendMsg(m) +} + +func (x *filterStreamInsertObjectServer) Recv() (*payload.Object_Blob, error) { + m := new(payload.Object_Blob) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _Filter_MultiInsertObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(payload.Object_Blob) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FilterServer).MultiInsertObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/filter.Filter/MultiInsertObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FilterServer).MultiInsertObject(ctx, req.(*payload.Object_Blob)) + } + return interceptor(ctx, in, info, handler) +} + +func _Filter_UpdateObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(payload.Object_Blob) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FilterServer).UpdateObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/filter.Filter/UpdateObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FilterServer).UpdateObject(ctx, req.(*payload.Object_Blob)) + } + return interceptor(ctx, in, info, handler) +} + +func _Filter_StreamUpdateObject_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(FilterServer).StreamUpdateObject(&filterStreamUpdateObjectServer{stream}) +} + +type Filter_StreamUpdateObjectServer interface { + Send(*payload.Empty) error + Recv() (*payload.Object_Blob, error) + grpc.ServerStream +} + +type filterStreamUpdateObjectServer struct { + grpc.ServerStream +} + +func (x *filterStreamUpdateObjectServer) Send(m *payload.Empty) error { + return x.ServerStream.SendMsg(m) +} + +func (x *filterStreamUpdateObjectServer) Recv() (*payload.Object_Blob, error) { + m := new(payload.Object_Blob) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _Filter_MultiUpdateObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(payload.Object_Blob) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FilterServer).MultiUpdateObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/filter.Filter/MultiUpdateObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FilterServer).MultiUpdateObject(ctx, req.(*payload.Object_Blob)) + } + return interceptor(ctx, in, info, handler) +} + +func _Filter_UpsertObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(payload.Object_Blob) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FilterServer).UpsertObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/filter.Filter/UpsertObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FilterServer).UpsertObject(ctx, req.(*payload.Object_Blob)) + } + return interceptor(ctx, in, info, handler) +} + +func _Filter_StreamUpsertObject_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(FilterServer).StreamUpsertObject(&filterStreamUpsertObjectServer{stream}) +} + +type Filter_StreamUpsertObjectServer interface { + Send(*payload.Empty) error + Recv() (*payload.Object_Blob, error) + grpc.ServerStream +} + +type filterStreamUpsertObjectServer struct { + grpc.ServerStream +} + +func (x *filterStreamUpsertObjectServer) Send(m *payload.Empty) error { + return x.ServerStream.SendMsg(m) +} + +func (x *filterStreamUpsertObjectServer) Recv() (*payload.Object_Blob, error) { + m := new(payload.Object_Blob) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _Filter_MultiUpsertObject_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(payload.Object_Blob) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FilterServer).MultiUpsertObject(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/filter.Filter/MultiUpsertObject", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FilterServer).MultiUpsertObject(ctx, req.(*payload.Object_Blob)) + } + return interceptor(ctx, in, info, handler) +} + +var _Filter_serviceDesc = grpc.ServiceDesc{ + ServiceName: "filter.Filter", + HandlerType: (*FilterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SearchObject", + Handler: _Filter_SearchObject_Handler, + }, + { + MethodName: "InsertObject", + Handler: _Filter_InsertObject_Handler, + }, + { + MethodName: "MultiInsertObject", + Handler: _Filter_MultiInsertObject_Handler, + }, + { + MethodName: "UpdateObject", + Handler: _Filter_UpdateObject_Handler, + }, + { + MethodName: "MultiUpdateObject", + Handler: _Filter_MultiUpdateObject_Handler, + }, + { + MethodName: "UpsertObject", + Handler: _Filter_UpsertObject_Handler, + }, + { + MethodName: "MultiUpsertObject", + Handler: _Filter_MultiUpsertObject_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "StreamSearch", + Handler: _Filter_StreamSearch_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "StreamInsertObject", + Handler: _Filter_StreamInsertObject_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "StreamUpdateObject", + Handler: _Filter_StreamUpdateObject_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "StreamUpsertObject", + Handler: _Filter_StreamUpsertObject_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "filter/filter.proto", +} diff --git a/apis/grpc/payload/payload.pb.go b/apis/grpc/payload/payload.pb.go index fb94a103e64..6a0d4258dde 100644 --- a/apis/grpc/payload/payload.pb.go +++ b/apis/grpc/payload/payload.pb.go @@ -187,6 +187,61 @@ func (m *Search_IDRequest) GetConfig() *Search_Config { return nil } +type Search_ObjectRequest struct { + Object []byte `protobuf:"bytes,1,opt,name=object,proto3" json:"object,omitempty"` + Config *Search_Config `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Search_ObjectRequest) Reset() { *m = Search_ObjectRequest{} } +func (m *Search_ObjectRequest) String() string { return proto.CompactTextString(m) } +func (*Search_ObjectRequest) ProtoMessage() {} +func (*Search_ObjectRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_678c914f1bee6d56, []int{0, 2} +} +func (m *Search_ObjectRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Search_ObjectRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Search_ObjectRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Search_ObjectRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_Search_ObjectRequest.Merge(m, src) +} +func (m *Search_ObjectRequest) XXX_Size() int { + return m.Size() +} +func (m *Search_ObjectRequest) XXX_DiscardUnknown() { + xxx_messageInfo_Search_ObjectRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_Search_ObjectRequest proto.InternalMessageInfo + +func (m *Search_ObjectRequest) GetObject() []byte { + if m != nil { + return m.Object + } + return nil +} + +func (m *Search_ObjectRequest) GetConfig() *Search_Config { + if m != nil { + return m.Config + } + return nil +} + type Search_Config struct { Num uint32 `protobuf:"varint,1,opt,name=num,proto3" json:"num,omitempty"` Radius float32 `protobuf:"fixed32,2,opt,name=radius,proto3" json:"radius,omitempty"` @@ -201,7 +256,7 @@ func (m *Search_Config) Reset() { *m = Search_Config{} } func (m *Search_Config) String() string { return proto.CompactTextString(m) } func (*Search_Config) ProtoMessage() {} func (*Search_Config) Descriptor() ([]byte, []int) { - return fileDescriptor_678c914f1bee6d56, []int{0, 2} + return fileDescriptor_678c914f1bee6d56, []int{0, 3} } func (m *Search_Config) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -269,7 +324,7 @@ func (m *Search_Response) Reset() { *m = Search_Response{} } func (m *Search_Response) String() string { return proto.CompactTextString(m) } func (*Search_Response) ProtoMessage() {} func (*Search_Response) Descriptor() ([]byte, []int) { - return fileDescriptor_678c914f1bee6d56, []int{0, 3} + return fileDescriptor_678c914f1bee6d56, []int{0, 4} } func (m *Search_Response) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -924,6 +979,61 @@ func (m *Object_Vectors) GetVectors() []*Object_Vector { return nil } +type Object_Blob struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Object []byte `protobuf:"bytes,2,opt,name=object,proto3" json:"object,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Object_Blob) Reset() { *m = Object_Blob{} } +func (m *Object_Blob) String() string { return proto.CompactTextString(m) } +func (*Object_Blob) ProtoMessage() {} +func (*Object_Blob) Descriptor() ([]byte, []int) { + return fileDescriptor_678c914f1bee6d56, []int{2, 5} +} +func (m *Object_Blob) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Object_Blob) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Object_Blob.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Object_Blob) XXX_Merge(src proto.Message) { + xxx_messageInfo_Object_Blob.Merge(m, src) +} +func (m *Object_Blob) XXX_Size() int { + return m.Size() +} +func (m *Object_Blob) XXX_DiscardUnknown() { + xxx_messageInfo_Object_Blob.DiscardUnknown(m) +} + +var xxx_messageInfo_Object_Blob proto.InternalMessageInfo + +func (m *Object_Blob) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *Object_Blob) GetObject() []byte { + if m != nil { + return m.Object + } + return nil +} + type Control struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -2967,6 +3077,7 @@ func init() { proto.RegisterType((*Search)(nil), "payload.Search") proto.RegisterType((*Search_Request)(nil), "payload.Search.Request") proto.RegisterType((*Search_IDRequest)(nil), "payload.Search.IDRequest") + proto.RegisterType((*Search_ObjectRequest)(nil), "payload.Search.ObjectRequest") proto.RegisterType((*Search_Config)(nil), "payload.Search.Config") proto.RegisterType((*Search_Response)(nil), "payload.Search.Response") proto.RegisterType((*Meta)(nil), "payload.Meta") @@ -2982,6 +3093,7 @@ func init() { proto.RegisterType((*Object_IDs)(nil), "payload.Object.IDs") proto.RegisterType((*Object_Vector)(nil), "payload.Object.Vector") proto.RegisterType((*Object_Vectors)(nil), "payload.Object.Vectors") + proto.RegisterType((*Object_Blob)(nil), "payload.Object.Blob") proto.RegisterType((*Control)(nil), "payload.Control") proto.RegisterType((*Control_CreateIndexRequest)(nil), "payload.Control.CreateIndexRequest") proto.RegisterType((*Replication)(nil), "payload.Replication") @@ -3028,90 +3140,93 @@ func init() { func init() { proto.RegisterFile("payload.proto", fileDescriptor_678c914f1bee6d56) } var fileDescriptor_678c914f1bee6d56 = []byte{ - // 1327 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xdd, 0x6e, 0x1b, 0xc5, - 0x17, 0xff, 0xef, 0x87, 0xd7, 0xf6, 0x49, 0xdc, 0x7f, 0x32, 0x2a, 0xa9, 0x3b, 0x40, 0x30, 0x2e, - 0x2d, 0x56, 0xa9, 0x6c, 0x9a, 0x22, 0x90, 0xa8, 0x04, 0xaa, 0x9d, 0x0a, 0x99, 0xd0, 0xd4, 0x9a, - 0xca, 0x11, 0xe2, 0x2b, 0x4c, 0xbc, 0x53, 0x67, 0xc9, 0x7a, 0x67, 0xd9, 0x9d, 0x75, 0xeb, 0xde, - 0xf3, 0x02, 0xdc, 0xf1, 0x16, 0x88, 0x6b, 0x1e, 0x80, 0x4b, 0x78, 0x02, 0x50, 0x91, 0xb8, 0xe2, - 0x09, 0x7a, 0x85, 0xe6, 0x63, 0xed, 0xb5, 0x93, 0xa2, 0x80, 0xb8, 0xca, 0x9c, 0x33, 0xbf, 0x73, - 0xe6, 0xfc, 0xce, 0x97, 0x37, 0x50, 0x8b, 0xe9, 0x2c, 0xe4, 0xd4, 0x6f, 0xc7, 0x09, 0x17, 0x1c, - 0x95, 0x8d, 0x88, 0x2f, 0x4d, 0x69, 0x18, 0xf8, 0x54, 0xb0, 0x4e, 0x7e, 0xd0, 0x88, 0xe6, 0xef, - 0x36, 0x78, 0x0f, 0x18, 0x4d, 0x46, 0xc7, 0xf8, 0x53, 0x28, 0x13, 0xf6, 0x75, 0xc6, 0x52, 0x81, - 0x1a, 0xe0, 0x4d, 0xd9, 0x48, 0xf0, 0xa4, 0x6e, 0x35, 0x9c, 0x96, 0xdd, 0xad, 0x3c, 0xeb, 0x96, - 0xbe, 0xb5, 0xec, 0x8a, 0x4d, 0x8c, 0x1e, 0xb5, 0xc1, 0x1b, 0xf1, 0xe8, 0x61, 0x30, 0xae, 0xdb, - 0x0d, 0xab, 0xb5, 0xb6, 0xb3, 0xd5, 0xce, 0x5f, 0xd6, 0xde, 0xda, 0x3d, 0x75, 0x4b, 0x0c, 0x0a, - 0xef, 0x41, 0xb5, 0xbf, 0x9b, 0xbb, 0xbf, 0x00, 0x76, 0xe0, 0xd7, 0xad, 0x86, 0xd5, 0xaa, 0x12, - 0x3b, 0xf0, 0xff, 0xb1, 0x33, 0x0e, 0x9e, 0xd6, 0xa0, 0xcb, 0xe0, 0x44, 0xd9, 0x44, 0xb9, 0xaa, - 0x75, 0xcb, 0xcf, 0xba, 0xee, 0x75, 0xbb, 0x65, 0x11, 0xa9, 0x43, 0x5b, 0xe0, 0x25, 0xd4, 0x0f, - 0xb2, 0x54, 0x39, 0xb5, 0x89, 0x91, 0x50, 0x1d, 0xca, 0x2c, 0x4e, 0x83, 0x90, 0x47, 0x75, 0x47, - 0x5d, 0xe4, 0xa2, 0xbc, 0x11, 0xc1, 0x84, 0xf1, 0x4c, 0xd4, 0xdd, 0x86, 0xd5, 0x72, 0x48, 0x2e, - 0xe2, 0xf7, 0xa0, 0x42, 0x58, 0x1a, 0xf3, 0x28, 0x65, 0x68, 0x07, 0xca, 0x09, 0x4b, 0xb3, 0x50, - 0xa4, 0x2a, 0x39, 0x6b, 0x3b, 0xf5, 0x79, 0xb4, 0xf7, 0x8f, 0xbe, 0x62, 0x23, 0xd1, 0xde, 0x0d, - 0x52, 0x41, 0xa3, 0x11, 0x23, 0x39, 0xb0, 0xf9, 0x8b, 0x05, 0xee, 0x3d, 0x26, 0x28, 0xbe, 0x04, - 0xce, 0x1e, 0x9b, 0xa1, 0x0d, 0x70, 0x4e, 0xd8, 0xcc, 0x64, 0x40, 0x1e, 0x31, 0x06, 0x77, 0x8f, - 0xcd, 0x52, 0x84, 0xc0, 0x3d, 0x61, 0x33, 0xed, 0xba, 0x4a, 0xd4, 0x59, 0x1a, 0x1d, 0xd0, 0x50, - 0x1a, 0x4d, 0x69, 0x98, 0x1b, 0x4d, 0x69, 0x28, 0x8d, 0x0e, 0x68, 0xa8, 0x8c, 0xa6, 0x34, 0x9c, - 0x1b, 0xc9, 0x33, 0xbe, 0x01, 0xde, 0x1e, 0x9b, 0x19, 0xbb, 0xe5, 0xc7, 0x72, 0x4f, 0xf6, 0xc2, - 0xd3, 0x4d, 0x28, 0x6b, 0x74, 0x8a, 0xae, 0x81, 0x73, 0x32, 0xcd, 0xb9, 0x5d, 0x9c, 0x73, 0x93, - 0xe1, 0xb7, 0x35, 0x86, 0x48, 0x40, 0xf3, 0x99, 0x05, 0x9e, 0x26, 0x8c, 0xdf, 0x86, 0x4a, 0xce, - 0xf9, 0x54, 0x6d, 0x31, 0x54, 0x7c, 0x73, 0x67, 0x0a, 0x31, 0x97, 0xf1, 0xcb, 0x60, 0xf7, 0x77, - 0xd1, 0xa5, 0x85, 0x85, 0x2a, 0x61, 0x62, 0x6f, 0x58, 0xd2, 0x54, 0xf2, 0xee, 0xef, 0xa6, 0x32, - 0xda, 0xc0, 0xcf, 0xc9, 0xc9, 0x23, 0xee, 0x81, 0x77, 0xa0, 0xdb, 0xf0, 0x79, 0xb6, 0x85, 0x0e, - 0xb6, 0xcf, 0xee, 0x60, 0x7c, 0x1b, 0xca, 0xda, 0x49, 0x8a, 0xde, 0x84, 0xb2, 0x56, 0xe6, 0xb4, - 0xb7, 0x56, 0x4b, 0xaa, 0x91, 0x24, 0x87, 0x35, 0xef, 0x42, 0xb9, 0xc7, 0x23, 0x91, 0xf0, 0x10, - 0xbf, 0x0b, 0xa8, 0x97, 0x30, 0x2a, 0x58, 0x3f, 0xf2, 0xd9, 0xe3, 0xbc, 0xc5, 0x5f, 0x83, 0x6a, - 0xcc, 0x79, 0x78, 0x98, 0x06, 0x4f, 0xd8, 0x72, 0x7b, 0xfe, 0x8f, 0x54, 0xe4, 0xcd, 0x83, 0xe0, - 0x09, 0x6b, 0x7e, 0x67, 0xc3, 0x1a, 0x61, 0x71, 0x18, 0x8c, 0xa8, 0x08, 0x78, 0x84, 0x6f, 0xca, - 0x3e, 0x1b, 0xf1, 0x29, 0x4b, 0x66, 0xe8, 0x2a, 0x5c, 0xf0, 0x59, 0xc8, 0x04, 0xf3, 0x0f, 0xe9, - 0x98, 0x45, 0x22, 0xcf, 0x40, 0xcd, 0x68, 0xef, 0x28, 0x25, 0xa6, 0x50, 0x25, 0xec, 0x88, 0x86, - 0x2a, 0xf9, 0xd7, 0x61, 0xf3, 0x38, 0x18, 0x1f, 0x1f, 0x66, 0x29, 0x1d, 0xb3, 0x65, 0xb3, 0xff, - 0xcb, 0x8b, 0xa1, 0xd4, 0x6b, 0x43, 0xd4, 0x82, 0x8d, 0x90, 0x3f, 0x5a, 0x86, 0xda, 0x0a, 0x7a, - 0x21, 0xe4, 0x8f, 0x0a, 0x48, 0x2c, 0xc0, 0x33, 0x36, 0x5b, 0xe0, 0x2d, 0x39, 0x35, 0x92, 0x8c, - 0x35, 0x61, 0x13, 0x3e, 0x5d, 0xc4, 0xaa, 0x3d, 0xd5, 0x8c, 0xd6, 0x98, 0xbf, 0x01, 0x9b, 0x49, - 0xce, 0x36, 0x1a, 0x6b, 0x68, 0xdd, 0x51, 0xc8, 0x8d, 0xc2, 0x85, 0x42, 0x37, 0x1f, 0x02, 0xec, - 0x06, 0xa9, 0x4a, 0x06, 0x4b, 0xf0, 0xc7, 0x8b, 0xe5, 0xf4, 0x22, 0xb8, 0x11, 0x9d, 0xb0, 0xd5, - 0xaa, 0x2b, 0x25, 0x7a, 0x09, 0xaa, 0xf2, 0x6f, 0x1a, 0x53, 0xd3, 0x6f, 0x55, 0xb2, 0x50, 0xc8, - 0x41, 0x89, 0xb8, 0xcf, 0xd4, 0xe0, 0x57, 0x89, 0x3a, 0x37, 0xff, 0x2c, 0x81, 0xd7, 0xa5, 0xa3, - 0x93, 0x2c, 0xc6, 0x43, 0xa8, 0x7e, 0xc0, 0x84, 0xae, 0x35, 0xbe, 0xb6, 0xf4, 0x62, 0x96, 0x9d, - 0xee, 0x33, 0xa5, 0xc4, 0x0d, 0x28, 0xdd, 0x7f, 0x14, 0x31, 0xdd, 0x8b, 0xf1, 0xe9, 0x5e, 0x8c, - 0xf1, 0x2d, 0xa8, 0x7e, 0xc4, 0x75, 0x85, 0xd3, 0x73, 0xbb, 0xfd, 0x12, 0x3c, 0xa2, 0x92, 0x77, - 0x6e, 0x8b, 0x36, 0xac, 0x1b, 0xdc, 0xbd, 0x2c, 0x14, 0x01, 0xda, 0x86, 0x92, 0xd4, 0x9b, 0x5a, - 0xcd, 0x27, 0xc0, 0x22, 0x5a, 0x8d, 0xbf, 0xb1, 0xc0, 0xee, 0x0f, 0xf0, 0xbe, 0xec, 0xb9, 0x71, - 0x90, 0x0a, 0x96, 0xe0, 0xee, 0xf9, 0x9e, 0x42, 0x18, 0x9c, 0x20, 0x36, 0x45, 0x2e, 0x38, 0x96, - 0x4a, 0xdc, 0x99, 0x07, 0x7e, 0x75, 0xe1, 0xcd, 0x18, 0x58, 0x67, 0x19, 0x1c, 0x03, 0xc8, 0xe5, - 0x62, 0x26, 0x1a, 0x15, 0xdf, 0x35, 0xcf, 0x21, 0x70, 0x27, 0x4c, 0x50, 0x53, 0x4f, 0x75, 0x2e, - 0x0c, 0xb8, 0xf3, 0x9c, 0x9f, 0xa8, 0x0d, 0xfd, 0xa6, 0x6b, 0xf6, 0x46, 0x2c, 0xf7, 0xc6, 0xda, - 0xe2, 0xa5, 0x14, 0xbd, 0xb5, 0x3a, 0xf6, 0x78, 0x3e, 0xf6, 0xba, 0x21, 0xda, 0x0b, 0xf4, 0x7c, - 0xf4, 0xf1, 0x8f, 0x16, 0x40, 0x8f, 0x4f, 0xe2, 0x84, 0xa5, 0x29, 0xf3, 0xf1, 0x17, 0xff, 0x2a, - 0xfa, 0xad, 0x42, 0xf4, 0x56, 0x6b, 0xfd, 0x6f, 0x62, 0xde, 0x5f, 0x8e, 0xf9, 0xfd, 0xd5, 0x98, - 0xaf, 0xae, 0xc6, 0xbc, 0x88, 0xed, 0xac, 0xf0, 0x9b, 0xdf, 0x97, 0xc1, 0xed, 0x47, 0x0f, 0x39, - 0xfe, 0xc1, 0x82, 0x92, 0x5a, 0x59, 0xf8, 0x73, 0x28, 0xf5, 0x78, 0x16, 0x09, 0x19, 0x55, 0x2a, - 0x78, 0xc2, 0x74, 0xfc, 0x35, 0x62, 0x24, 0xd4, 0x80, 0xb5, 0x2c, 0x1a, 0xf1, 0xc9, 0x24, 0x10, - 0x82, 0xf9, 0x8a, 0x48, 0x8d, 0x14, 0x55, 0x72, 0xcb, 0x07, 0xd2, 0x57, 0x10, 0x8d, 0x15, 0xa3, - 0x0a, 0x99, 0xcb, 0xf8, 0x43, 0x70, 0x87, 0xc3, 0xfe, 0x2e, 0x7e, 0x05, 0xaa, 0xbd, 0xb9, 0xc1, - 0x19, 0x89, 0xc2, 0xaf, 0xc2, 0xda, 0xb0, 0xe0, 0xf3, 0x2c, 0xc8, 0x1f, 0x16, 0x38, 0x03, 0xee, - 0xa3, 0xcb, 0x50, 0xa1, 0x71, 0x7c, 0xb8, 0xd8, 0x03, 0xa4, 0x4c, 0xe3, 0x78, 0x5f, 0x6e, 0x00, - 0x64, 0xd6, 0x83, 0x49, 0xf7, 0xe9, 0xad, 0xe0, 0xac, 0x6e, 0x05, 0x3d, 0xb8, 0x6e, 0xa1, 0xd1, - 0x1f, 0xab, 0xc1, 0x45, 0x57, 0xc0, 0x19, 0xc5, 0x59, 0xbd, 0xa4, 0x3e, 0x4a, 0x36, 0xe7, 0x89, - 0x96, 0xe9, 0x6b, 0xf7, 0x06, 0x43, 0x22, 0x6f, 0xd1, 0x0d, 0xf0, 0x26, 0x6c, 0xc2, 0x93, 0x59, - 0xdd, 0x53, 0xb8, 0x8b, 0xcb, 0xb8, 0x7b, 0xea, 0x8e, 0x18, 0x0c, 0xba, 0x66, 0x36, 0x50, 0x59, - 0x61, 0xd1, 0x32, 0x76, 0x9f, 0xfb, 0x4c, 0x6f, 0x25, 0xfc, 0xab, 0x05, 0xae, 0x14, 0xe7, 0x74, - 0xac, 0x02, 0x9d, 0x2b, 0x50, 0x0b, 0x22, 0xc1, 0x92, 0x88, 0x86, 0x87, 0xd4, 0xf7, 0x13, 0xc3, - 0x75, 0x3d, 0x57, 0xde, 0xf1, 0xfd, 0x44, 0x82, 0xd8, 0xe3, 0x22, 0x48, 0xf3, 0x5e, 0xcf, 0x95, - 0x06, 0xa4, 0x18, 0xba, 0xe7, 0x64, 0x58, 0x3a, 0x1f, 0xc3, 0x01, 0xf7, 0x53, 0x93, 0x8d, 0x15, - 0x86, 0xf2, 0x86, 0xa8, 0x7b, 0xbc, 0x07, 0x4e, 0x6f, 0x30, 0x44, 0x17, 0xa1, 0x14, 0x06, 0x93, - 0x40, 0x28, 0x82, 0x16, 0xd1, 0x82, 0xfc, 0x14, 0x4b, 0xf4, 0xea, 0x50, 0xdc, 0x2c, 0x92, 0x8b, - 0x12, 0xaf, 0x7e, 0xb2, 0x14, 0x1d, 0xb9, 0xcb, 0xa4, 0x80, 0xf7, 0xc1, 0xd3, 0x61, 0xfc, 0x47, - 0xfe, 0xde, 0xd1, 0x24, 0x50, 0x07, 0xdc, 0x98, 0xfb, 0xf9, 0xac, 0x6d, 0x9e, 0x22, 0x53, 0xd8, - 0x65, 0x0a, 0x88, 0x6f, 0x43, 0x49, 0x96, 0x2d, 0x45, 0x3b, 0x50, 0x92, 0x85, 0xcc, 0x4d, 0xcf, - 0xa8, 0x74, 0x71, 0x23, 0x2b, 0x28, 0x7e, 0x01, 0x9c, 0xfe, 0x20, 0x55, 0x9f, 0x50, 0xb1, 0xf9, - 0x85, 0xb5, 0x83, 0xb8, 0x59, 0x86, 0xd2, 0xdd, 0x49, 0x2c, 0x66, 0xdd, 0xcf, 0x7e, 0x7a, 0xba, - 0x6d, 0xfd, 0xfc, 0x74, 0xdb, 0xfa, 0xed, 0xe9, 0xb6, 0x05, 0x5b, 0x3c, 0x19, 0xb7, 0xa7, 0x3e, - 0xa5, 0x69, 0x7b, 0x4a, 0x43, 0x3f, 0x7f, 0xa0, 0xbb, 0x76, 0x40, 0x43, 0x7f, 0xa0, 0x85, 0x81, - 0xf5, 0xc9, 0xeb, 0xe3, 0x40, 0x1c, 0x67, 0x47, 0xed, 0x11, 0x9f, 0x74, 0x14, 0x5a, 0xfe, 0x0b, - 0xe0, 0x77, 0x68, 0x1c, 0xa4, 0x9d, 0x71, 0x12, 0x8f, 0x3a, 0xc6, 0xee, 0xc8, 0x53, 0xff, 0x11, - 0xdc, 0xfa, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xa2, 0x9a, 0x9b, 0x8a, 0x44, 0x0c, 0x00, 0x00, + // 1362 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0x5d, 0x6f, 0x1b, 0x45, + 0x17, 0x7e, 0xf7, 0xc3, 0x6b, 0xfb, 0x24, 0xee, 0x9b, 0x8c, 0xfa, 0xa6, 0xee, 0xbc, 0x10, 0x8c, + 0x4b, 0x4b, 0x54, 0x2a, 0x9b, 0xa6, 0x88, 0x4a, 0x54, 0x02, 0xd5, 0x4e, 0x85, 0x4c, 0x68, 0x6a, + 0x4d, 0xe5, 0x80, 0xf8, 0x0a, 0x13, 0xef, 0xd4, 0x59, 0xb2, 0xde, 0x59, 0x76, 0x76, 0xdd, 0xba, + 0xf7, 0xfc, 0x01, 0xee, 0xf8, 0x17, 0x08, 0x6e, 0xfb, 0x03, 0xb8, 0x84, 0x5f, 0x00, 0xea, 0x05, + 0x57, 0xfc, 0x82, 0x5e, 0xa1, 0xf9, 0x58, 0x7b, 0xed, 0x24, 0x52, 0x8a, 0xb8, 0xca, 0x9c, 0x33, + 0xcf, 0x39, 0x73, 0x9e, 0x39, 0x67, 0x9e, 0x75, 0xa0, 0x16, 0xd3, 0x69, 0xc8, 0xa9, 0xdf, 0x8a, + 0x13, 0x9e, 0x72, 0x54, 0x36, 0x26, 0xbe, 0x34, 0xa1, 0x61, 0xe0, 0xd3, 0x94, 0xb5, 0xf3, 0x85, + 0x46, 0x34, 0x9f, 0x39, 0xe0, 0x3d, 0x64, 0x34, 0x19, 0x1e, 0xe1, 0xcf, 0xa1, 0x4c, 0xd8, 0xb7, + 0x19, 0x13, 0x29, 0x6a, 0x80, 0x37, 0x61, 0xc3, 0x94, 0x27, 0x75, 0xab, 0xe1, 0x6c, 0xd9, 0x9d, + 0xca, 0x8b, 0x4e, 0xe9, 0x7b, 0xcb, 0xae, 0xd8, 0xc4, 0xf8, 0x51, 0x0b, 0xbc, 0x21, 0x8f, 0x1e, + 0x05, 0xa3, 0xba, 0xdd, 0xb0, 0xb6, 0x56, 0xb6, 0x37, 0x5a, 0xf9, 0xc9, 0x3a, 0x5b, 0xab, 0xab, + 0x76, 0x89, 0x41, 0xe1, 0x5d, 0xa8, 0xf6, 0x76, 0xf2, 0xf4, 0x17, 0xc0, 0x0e, 0xfc, 0xba, 0xd5, + 0xb0, 0xb6, 0xaa, 0xc4, 0x0e, 0xfc, 0x97, 0x4e, 0xf6, 0x09, 0xd4, 0x1e, 0x1c, 0x7e, 0xc3, 0x86, + 0x69, 0x9e, 0x70, 0x03, 0x3c, 0xae, 0x1c, 0x2a, 0xe9, 0x2a, 0x31, 0xd6, 0x4b, 0x27, 0xe6, 0xe0, + 0x69, 0x0f, 0xba, 0x0c, 0x4e, 0x94, 0x8d, 0x55, 0xba, 0x5a, 0xa7, 0xfc, 0xa2, 0xe3, 0x5e, 0xb7, + 0xb7, 0x2c, 0x22, 0x7d, 0xf2, 0xb0, 0x84, 0xfa, 0x41, 0x26, 0x54, 0x52, 0x9b, 0x18, 0x0b, 0xd5, + 0xa1, 0xcc, 0x62, 0x11, 0x84, 0x3c, 0xaa, 0x3b, 0x6a, 0x23, 0x37, 0xe5, 0x4e, 0x1a, 0x8c, 0x19, + 0xcf, 0xd2, 0xba, 0xdb, 0xb0, 0xb6, 0x1c, 0x92, 0x9b, 0xf8, 0x7d, 0xa8, 0x10, 0x26, 0x62, 0x1e, + 0x09, 0x86, 0xb6, 0xa1, 0x9c, 0x30, 0x91, 0x85, 0xa9, 0x50, 0xb7, 0xbe, 0xb2, 0x5d, 0x9f, 0x55, + 0xab, 0xd9, 0xb6, 0x76, 0x02, 0x91, 0xd2, 0x68, 0xc8, 0x48, 0x0e, 0x6c, 0xfe, 0x66, 0x81, 0x7b, + 0x9f, 0xa5, 0x14, 0x5f, 0x02, 0x67, 0x97, 0x4d, 0xd1, 0x1a, 0x38, 0xc7, 0x6c, 0x6a, 0xae, 0x56, + 0x2e, 0x31, 0x06, 0x77, 0x97, 0x4d, 0x05, 0x42, 0xe0, 0x1e, 0xb3, 0xa9, 0x4e, 0x5d, 0x25, 0x6a, + 0x2d, 0x83, 0xf6, 0x69, 0x28, 0x83, 0x26, 0x34, 0xcc, 0x83, 0x26, 0x34, 0x94, 0x41, 0xfb, 0x34, + 0x54, 0x41, 0x13, 0x1a, 0xce, 0x82, 0xe4, 0x1a, 0xdf, 0x00, 0x6f, 0x97, 0x4d, 0x4d, 0xdc, 0xe2, + 0x61, 0x79, 0x26, 0x7b, 0x9e, 0xe9, 0x26, 0x94, 0x35, 0x5a, 0xa0, 0x6b, 0xe0, 0x1c, 0x4f, 0x72, + 0x6e, 0x17, 0x67, 0xdc, 0x64, 0xf9, 0x2d, 0x8d, 0x21, 0x12, 0xd0, 0xfc, 0xd9, 0x06, 0x4f, 0x13, + 0xc6, 0xef, 0x42, 0x25, 0xe7, 0x7c, 0x62, 0x68, 0x30, 0x54, 0x7c, 0xb3, 0x67, 0x1a, 0x31, 0xb3, + 0xf1, 0xab, 0x60, 0xf7, 0x76, 0xd0, 0xa5, 0x79, 0x84, 0x6a, 0x61, 0x62, 0xaf, 0x59, 0x32, 0x54, + 0xf2, 0xee, 0xed, 0x08, 0x59, 0x6d, 0xe0, 0xe7, 0xe4, 0xe4, 0x12, 0x77, 0xc1, 0xdb, 0xd7, 0xf3, + 0x7d, 0x56, 0x6c, 0xe1, 0x69, 0xd8, 0xa7, 0x3f, 0x0d, 0x7c, 0x07, 0xca, 0x3a, 0x89, 0x40, 0x6f, + 0x43, 0x59, 0x3b, 0x73, 0xda, 0x1b, 0xcb, 0x2d, 0xd5, 0x48, 0x92, 0xc3, 0xf0, 0x6d, 0x70, 0x3b, + 0x21, 0x3f, 0x3c, 0xfb, 0xfc, 0xf9, 0xa8, 0xdb, 0xc5, 0x51, 0x6f, 0xde, 0x83, 0x72, 0x97, 0x47, + 0x69, 0xc2, 0x43, 0xfc, 0x1e, 0xa0, 0x6e, 0xc2, 0x68, 0xca, 0x7a, 0x91, 0xcf, 0x9e, 0xe4, 0x6f, + 0xe4, 0x0d, 0xa8, 0xc6, 0x9c, 0x87, 0x07, 0x22, 0x78, 0xca, 0x16, 0xe7, 0xfa, 0x3f, 0xa4, 0x22, + 0x77, 0x1e, 0x06, 0x4f, 0x59, 0xf3, 0x07, 0x1b, 0x56, 0x08, 0x8b, 0xc3, 0x60, 0x48, 0xd3, 0x80, + 0x47, 0xf8, 0xa6, 0x1c, 0xd0, 0x21, 0x9f, 0xb0, 0x64, 0x8a, 0xae, 0xc2, 0x05, 0x9f, 0x85, 0x2c, + 0x65, 0xfe, 0x01, 0x1d, 0xb1, 0x28, 0xcd, 0xaf, 0xae, 0x66, 0xbc, 0x77, 0x95, 0x13, 0x53, 0xa8, + 0x12, 0x76, 0x48, 0x43, 0xd5, 0xb5, 0xeb, 0xb0, 0x7e, 0x14, 0x8c, 0x8e, 0x0e, 0x32, 0x41, 0x47, + 0x6c, 0x31, 0xec, 0xbf, 0x72, 0x63, 0x20, 0xfd, 0x3a, 0x10, 0x6d, 0xc1, 0x5a, 0xc8, 0x1f, 0x2f, + 0x42, 0x6d, 0x05, 0xbd, 0x10, 0xf2, 0xc7, 0x05, 0x24, 0x4e, 0xc1, 0x33, 0x31, 0x1b, 0xe0, 0x2d, + 0x24, 0x35, 0x96, 0xac, 0x35, 0x61, 0x63, 0x3e, 0x99, 0xd7, 0xaa, 0x33, 0xd5, 0x8c, 0xd7, 0x84, + 0xbf, 0x05, 0xeb, 0x49, 0xce, 0x36, 0x1a, 0x69, 0x68, 0xdd, 0x51, 0xc8, 0xb5, 0xc2, 0x86, 0x42, + 0x37, 0x1f, 0x01, 0xec, 0x04, 0x42, 0x5d, 0x06, 0x4b, 0xf0, 0xa7, 0x73, 0xb9, 0xfc, 0x3f, 0xb8, + 0x11, 0x1d, 0xb3, 0xe5, 0x76, 0x29, 0x27, 0x7a, 0x05, 0xaa, 0xf2, 0xaf, 0x88, 0xa9, 0x19, 0xd4, + 0x2a, 0x99, 0x3b, 0xe4, 0x0b, 0x8b, 0xb8, 0xcf, 0x94, 0x62, 0x54, 0x89, 0x5a, 0x37, 0xff, 0x2a, + 0x81, 0xd7, 0xa1, 0xc3, 0xe3, 0x2c, 0xc6, 0x03, 0xa8, 0x7e, 0xc8, 0x52, 0x3d, 0x24, 0xf8, 0xda, + 0xc2, 0x89, 0x59, 0x76, 0x72, 0x40, 0x94, 0x13, 0x37, 0xa0, 0xf4, 0xe0, 0x71, 0xc4, 0xf4, 0x10, + 0xc7, 0x27, 0x87, 0x28, 0xc6, 0xb7, 0xa0, 0xfa, 0x31, 0xd7, 0x1d, 0x16, 0xe7, 0x4e, 0xfb, 0x35, + 0x78, 0x44, 0x5d, 0xde, 0xb9, 0x23, 0x5a, 0xb0, 0x6a, 0x70, 0xf7, 0xb3, 0x30, 0x0d, 0xd0, 0x26, + 0x94, 0xa4, 0xdf, 0xf4, 0x6a, 0xf6, 0x74, 0x2c, 0xa2, 0xdd, 0xf8, 0x3b, 0x0b, 0xec, 0x5e, 0x1f, + 0xef, 0xc9, 0x99, 0x1b, 0x05, 0x22, 0x65, 0x09, 0xee, 0x9c, 0xef, 0x28, 0x84, 0xc1, 0x09, 0x62, + 0xd3, 0xe4, 0x42, 0x62, 0xe9, 0xc4, 0xed, 0x59, 0xe1, 0x57, 0xe7, 0xd9, 0x4c, 0x80, 0x75, 0x5a, + 0xc0, 0x11, 0x80, 0x54, 0x25, 0x23, 0x05, 0xa8, 0x78, 0xae, 0x39, 0x0e, 0x81, 0x3b, 0x66, 0x29, + 0x35, 0xfd, 0x54, 0xeb, 0x82, 0x32, 0x38, 0x67, 0x7c, 0x34, 0xd7, 0xf4, 0x99, 0xae, 0x11, 0x9c, + 0x58, 0x0a, 0xce, 0xca, 0xfc, 0x24, 0x81, 0xde, 0x59, 0xd6, 0x0b, 0x3c, 0xd3, 0x0b, 0x3d, 0x10, + 0xad, 0x39, 0x7a, 0xae, 0x19, 0xcf, 0x2c, 0x80, 0x2e, 0x1f, 0xc7, 0x09, 0x13, 0x82, 0xf9, 0xf8, + 0xab, 0x7f, 0x54, 0xfd, 0x46, 0xa1, 0x7a, 0xa5, 0x2b, 0x67, 0xd6, 0xbc, 0xb7, 0x58, 0xf3, 0x07, + 0xcb, 0x35, 0x5f, 0x5d, 0xae, 0x79, 0x5e, 0xdb, 0x69, 0xe5, 0x37, 0x7f, 0x2c, 0x83, 0xdb, 0x8b, + 0x1e, 0x71, 0xfc, 0x93, 0x05, 0x25, 0x25, 0x59, 0xf8, 0x4b, 0x28, 0x75, 0x79, 0x16, 0xa9, 0x0f, + 0xbb, 0x48, 0x79, 0xc2, 0x74, 0xfd, 0x35, 0x62, 0x2c, 0xd4, 0x80, 0x95, 0x2c, 0x1a, 0xf2, 0xf1, + 0x38, 0x48, 0x53, 0xe6, 0x2b, 0x22, 0x35, 0x52, 0x74, 0xc9, 0xcf, 0x43, 0x20, 0x73, 0x05, 0xd1, + 0x48, 0x31, 0xaa, 0x90, 0x99, 0x8d, 0x3f, 0x02, 0x77, 0x30, 0xe8, 0xed, 0xe0, 0xd7, 0xa0, 0xda, + 0x9d, 0x05, 0x9c, 0x72, 0x51, 0xf8, 0x75, 0x58, 0x19, 0x14, 0x72, 0x9e, 0x06, 0xf9, 0xd3, 0x02, + 0xa7, 0xcf, 0x7d, 0x74, 0x19, 0x2a, 0x34, 0x8e, 0x0f, 0xe6, 0x3a, 0x40, 0xca, 0x34, 0x8e, 0xf7, + 0xa4, 0x02, 0x20, 0x23, 0x0f, 0xe6, 0xba, 0x4f, 0xaa, 0x82, 0xb3, 0xac, 0x0a, 0xfa, 0xe1, 0xba, + 0x85, 0x41, 0x7f, 0xa2, 0x1e, 0x2e, 0xba, 0x02, 0xce, 0x30, 0xce, 0xea, 0x25, 0xf5, 0x6b, 0x66, + 0x7d, 0x76, 0xd1, 0xf2, 0xfa, 0x5a, 0xdd, 0xfe, 0x80, 0xc8, 0x5d, 0x74, 0x03, 0xbc, 0x31, 0x1b, + 0xf3, 0x64, 0x5a, 0xf7, 0x14, 0xee, 0xe2, 0x22, 0xee, 0xbe, 0xda, 0x23, 0x06, 0x83, 0xae, 0x19, + 0x05, 0x2a, 0x2b, 0x2c, 0x5a, 0xc4, 0xee, 0x71, 0x9f, 0x69, 0x55, 0xc2, 0xbf, 0x5b, 0xe0, 0x4a, + 0x73, 0x46, 0xc7, 0x2a, 0xd0, 0xb9, 0x02, 0xb5, 0x20, 0x4a, 0x59, 0x12, 0xd1, 0xf0, 0x80, 0xfa, + 0x7e, 0x62, 0xb8, 0xae, 0xe6, 0xce, 0xbb, 0xbe, 0x9f, 0x48, 0x10, 0x7b, 0x52, 0x04, 0x69, 0xde, + 0xab, 0xb9, 0xd3, 0x80, 0x14, 0x43, 0xf7, 0x9c, 0x0c, 0x4b, 0xe7, 0x63, 0xd8, 0xe7, 0xbe, 0x30, + 0xb7, 0xb1, 0xc4, 0x50, 0xee, 0x10, 0xb5, 0x8f, 0x77, 0xc1, 0xe9, 0xf6, 0x07, 0xe8, 0x22, 0x94, + 0xc2, 0x60, 0x1c, 0xe8, 0xdf, 0x92, 0x16, 0xd1, 0x86, 0xfc, 0x0d, 0x97, 0x68, 0xe9, 0x50, 0xdc, + 0x2c, 0x92, 0x9b, 0x12, 0xaf, 0x3e, 0x59, 0x8a, 0x8e, 0xd4, 0x32, 0x69, 0xe0, 0x3d, 0xf0, 0x74, + 0x19, 0xff, 0x52, 0xbe, 0xdb, 0x9a, 0x04, 0x6a, 0x83, 0x1b, 0x73, 0x3f, 0x7f, 0x6b, 0xeb, 0x27, + 0xc8, 0x14, 0xb4, 0x4c, 0x01, 0xf1, 0x1d, 0x28, 0xc9, 0xb6, 0x09, 0xb4, 0x0d, 0x25, 0xd9, 0xc8, + 0x3c, 0xf4, 0x94, 0x4e, 0x17, 0x15, 0x59, 0x41, 0xf1, 0xff, 0xc0, 0xe9, 0xf5, 0x85, 0xfa, 0xed, + 0x15, 0x9b, 0x2f, 0xac, 0x1d, 0xc4, 0xcd, 0x32, 0x94, 0xee, 0x8d, 0xe3, 0x74, 0xda, 0xf9, 0xe2, + 0x97, 0xe7, 0x9b, 0xd6, 0xaf, 0xcf, 0x37, 0xad, 0x3f, 0x9e, 0x6f, 0x5a, 0xb0, 0xc1, 0x93, 0x51, + 0x6b, 0xe2, 0x53, 0x2a, 0x5a, 0x13, 0x1a, 0xfa, 0xf9, 0x01, 0x9d, 0x95, 0x7d, 0x1a, 0xfa, 0x7d, + 0x6d, 0xf4, 0xad, 0xcf, 0xde, 0x1c, 0x05, 0xe9, 0x51, 0x76, 0xd8, 0x1a, 0xf2, 0x71, 0x5b, 0xa1, + 0xe5, 0x3f, 0x25, 0x7e, 0x9b, 0xc6, 0x81, 0x68, 0x8f, 0x92, 0x78, 0xd8, 0x36, 0x71, 0x87, 0x9e, + 0xfa, 0x1f, 0xe5, 0xd6, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x6d, 0xee, 0x4b, 0xff, 0xd6, 0x0c, + 0x00, 0x00, } func (m *Search) Marshal() (dAtA []byte, err error) { @@ -3236,6 +3351,52 @@ func (m *Search_IDRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Search_ObjectRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Search_ObjectRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Search_ObjectRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Config != nil { + { + size, err := m.Config.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPayload(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Object) > 0 { + i -= len(m.Object) + copy(dAtA[i:], m.Object) + i = encodeVarintPayload(dAtA, i, uint64(len(m.Object))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Search_Config) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -3738,9 +3899,9 @@ func (m *Object_Vector) MarshalToSizedBuffer(dAtA []byte) (int, error) { } if len(m.Vector) > 0 { for iNdEx := len(m.Vector) - 1; iNdEx >= 0; iNdEx-- { - f4 := math.Float32bits(float32(m.Vector[iNdEx])) + f5 := math.Float32bits(float32(m.Vector[iNdEx])) i -= 4 - encoding_binary.LittleEndian.PutUint32(dAtA[i:], uint32(f4)) + encoding_binary.LittleEndian.PutUint32(dAtA[i:], uint32(f5)) } i = encodeVarintPayload(dAtA, i, uint64(len(m.Vector)*4)) i-- @@ -3797,6 +3958,47 @@ func (m *Object_Vectors) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Object_Blob) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Object_Blob) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Object_Blob) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Object) > 0 { + i -= len(m.Object) + copy(dAtA[i:], m.Object) + i = encodeVarintPayload(dAtA, i, uint64(len(m.Object))) + i-- + dAtA[i] = 0x12 + } + if len(m.Id) > 0 { + i -= len(m.Id) + copy(dAtA[i:], m.Id) + i = encodeVarintPayload(dAtA, i, uint64(len(m.Id))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *Control) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4568,9 +4770,9 @@ func (m *Backup_MetaVector) MarshalToSizedBuffer(dAtA []byte) (int, error) { } if len(m.Vector) > 0 { for iNdEx := len(m.Vector) - 1; iNdEx >= 0; iNdEx-- { - f5 := math.Float32bits(float32(m.Vector[iNdEx])) + f6 := math.Float32bits(float32(m.Vector[iNdEx])) i -= 4 - encoding_binary.LittleEndian.PutUint32(dAtA[i:], uint32(f5)) + encoding_binary.LittleEndian.PutUint32(dAtA[i:], uint32(f6)) } i = encodeVarintPayload(dAtA, i, uint64(len(m.Vector)*4)) i-- @@ -5427,6 +5629,26 @@ func (m *Search_IDRequest) Size() (n int) { return n } +func (m *Search_ObjectRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Object) + if l > 0 { + n += 1 + l + sovPayload(uint64(l)) + } + if m.Config != nil { + l = m.Config.Size() + n += 1 + l + sovPayload(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *Search_Config) Size() (n int) { if m == nil { return 0 @@ -5689,6 +5911,26 @@ func (m *Object_Vectors) Size() (n int) { return n } +func (m *Object_Blob) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Id) + if l > 0 { + n += 1 + l + sovPayload(uint64(l)) + } + l = len(m.Object) + if l > 0 { + n += 1 + l + sovPayload(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *Control) Size() (n int) { if m == nil { return 0 @@ -6748,6 +6990,130 @@ func (m *Search_IDRequest) Unmarshal(dAtA []byte) error { } return nil } +func (m *Search_ObjectRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPayload + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ObjectRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ObjectRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Object", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPayload + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPayload + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPayload + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Object = append(m.Object[:0], dAtA[iNdEx:postIndex]...) + if m.Object == nil { + m.Object = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPayload + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPayload + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPayload + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Config == nil { + m.Config = &Search_Config{} + } + if err := m.Config.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPayload(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPayload + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthPayload + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Search_Config) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -8105,6 +8471,126 @@ func (m *Object_Vectors) Unmarshal(dAtA []byte) error { } return nil } +func (m *Object_Blob) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPayload + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Blob: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Blob: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPayload + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPayload + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPayload + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Id = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Object", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPayload + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPayload + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPayload + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Object = append(m.Object[:0], dAtA[iNdEx:postIndex]...) + if m.Object == nil { + m.Object = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPayload(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPayload + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthPayload + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Control) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/apis/proto/filter/ingress/ingress_filter.proto b/apis/proto/filter/ingress/ingress_filter.proto index cdea89d0bdd..1d21a614676 100644 --- a/apis/proto/filter/ingress/ingress_filter.proto +++ b/apis/proto/filter/ingress/ingress_filter.proto @@ -27,4 +27,23 @@ import "payload.proto"; import "google/api/annotations.proto"; import "pb/gql.proto"; -service IngressFilter {} +service IngressFilter { + rpc GenVector(payload.Object.Blob) returns (payload.Object.Vector) { + option (google.api.http) = { + post : "/object" + body : "*" + }; + } + rpc StreamGenVector(stream payload.Object.Blob) + returns (stream payload.Object.Vector) {} + + rpc FilterVector(payload.Object.Vector) returns (payload.Object.Vector) { + option (google.api.http) = { + post : "/vector" + body : "*" + }; + option (gql.rpc_type) = MUTATION; + } + rpc StreamFilterVector(stream payload.Object.Vector) + returns (stream payload.Object.Vector) {} +} diff --git a/apis/proto/gateway/filter/filter.proto b/apis/proto/gateway/filter/filter.proto new file mode 100644 index 00000000000..bc027e1c191 --- /dev/null +++ b/apis/proto/gateway/filter/filter.proto @@ -0,0 +1,72 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +syntax = "proto3"; + +package filter; + +option go_package = "github.com/vdaas/vald/apis/grpc/gateway/filter"; +option java_multiple_files = true; +option java_package = "org.vdaas.vald.gateway.filter"; +option java_outer_classname = "ValdFilterGateway"; + +import "payload.proto"; +import "google/api/annotations.proto"; +import "pb/gql.proto"; + +service Filter { + rpc SearchObject(payload.Search.ObjectRequest) returns (payload.Search.Response) { + option (google.api.http) = { + post : "/search/object" + body : "*" + }; + } + rpc StreamSearch(stream payload.Search.ObjectRequest) + returns (stream payload.Search.Response) {} + + rpc InsertObject(payload.Object.Blob) returns (payload.Empty) { + option (google.api.http) = { + post : "/insert/object" + body : "*" + }; + option (gql.rpc_type) = MUTATION; + } + rpc StreamInsertObject(stream payload.Object.Blob) + returns (stream payload.Empty) {} + rpc MultiInsertObject(payload.Object.Blob) returns (payload.Empty) {} + + rpc UpdateObject(payload.Object.Blob) returns (payload.Empty) { + option (google.api.http) = { + post : "/update/object" + body : "*" + }; + option (gql.rpc_type) = MUTATION; + } + rpc StreamUpdateObject(stream payload.Object.Blob) + returns (stream payload.Empty) {} + rpc MultiUpdateObject(payload.Object.Blob) returns (payload.Empty) {} + + rpc UpsertObject(payload.Object.Blob) returns (payload.Empty) { + option (google.api.http) = { + post : "/upsert/object" + body : "*" + }; + option (gql.rpc_type) = MUTATION; + } + rpc StreamUpsertObject(stream payload.Object.Blob) + returns (stream payload.Empty) {} + rpc MultiUpsertObject(payload.Object.Blob) returns (payload.Empty) {} +} diff --git a/apis/proto/payload/payload.proto b/apis/proto/payload/payload.proto index 37838684cbb..702a88e5cf5 100644 --- a/apis/proto/payload/payload.proto +++ b/apis/proto/payload/payload.proto @@ -39,6 +39,11 @@ message Search { Config config = 2; } + message ObjectRequest { + bytes object = 1; + Config config = 2; + } + message Config { uint32 num = 1 [ (validate.rules).uint32.gte = 1 ]; float radius = 2; @@ -75,6 +80,11 @@ message Object { repeated float vector = 2 [ (validate.rules).repeated .min_items = 2 ]; } message Vectors { repeated Vector vectors = 1; } + + message Blob { + string id = 1 [ (validate.rules).string.min_len = 1 ]; + bytes object = 2; + } } message Control { diff --git a/apis/swagger/filter/ingress/ingress/ingress_filter.swagger.json b/apis/swagger/filter/ingress/ingress/ingress_filter.swagger.json index 0f7da1b4065..b3951dd983c 100644 --- a/apis/swagger/filter/ingress/ingress/ingress_filter.swagger.json +++ b/apis/swagger/filter/ingress/ingress/ingress_filter.swagger.json @@ -10,8 +10,100 @@ "produces": [ "application/json" ], - "paths": {}, + "paths": { + "/object": { + "post": { + "operationId": "IngressFilter_GenVector", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/ObjectVector" + } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/runtimeError" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ObjectBlob" + } + } + ], + "tags": [ + "IngressFilter" + ] + } + }, + "/vector": { + "post": { + "operationId": "IngressFilter_FilterVector", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/ObjectVector" + } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/runtimeError" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ObjectVector" + } + } + ], + "tags": [ + "IngressFilter" + ] + } + } + }, "definitions": { + "ObjectBlob": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "object": { + "type": "string", + "format": "byte" + } + } + }, + "ObjectVector": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "vector": { + "type": "array", + "items": { + "type": "number", + "format": "float" + } + } + } + }, "protobufAny": { "type": "object", "properties": { @@ -44,6 +136,31 @@ } } } + }, + "runtimeStreamError": { + "type": "object", + "properties": { + "grpcCode": { + "type": "integer", + "format": "int32" + }, + "httpCode": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "httpStatus": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + } + } + } } } } diff --git a/apis/swagger/gateway/filter/filter/filter.swagger.json b/apis/swagger/gateway/filter/filter/filter.swagger.json new file mode 100644 index 00000000000..1185f5bfe62 --- /dev/null +++ b/apis/swagger/gateway/filter/filter/filter.swagger.json @@ -0,0 +1,274 @@ +{ + "swagger": "2.0", + "info": { + "title": "filter/filter.proto", + "version": "version not set" + }, + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/insert/object": { + "post": { + "operationId": "Filter_InsertObject", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/payloadEmpty" + } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/runtimeError" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ObjectBlob" + } + } + ], + "tags": [ + "Filter" + ] + } + }, + "/search/object": { + "post": { + "operationId": "Filter_SearchObject", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/SearchResponse" + } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/runtimeError" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SearchObjectRequest" + } + } + ], + "tags": [ + "Filter" + ] + } + }, + "/update/object": { + "post": { + "operationId": "Filter_UpdateObject", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/payloadEmpty" + } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/runtimeError" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ObjectBlob" + } + } + ], + "tags": [ + "Filter" + ] + } + }, + "/upsert/object": { + "post": { + "operationId": "Filter_UpsertObject", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/payloadEmpty" + } + }, + "default": { + "description": "An unexpected error response", + "schema": { + "$ref": "#/definitions/runtimeError" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ObjectBlob" + } + } + ], + "tags": [ + "Filter" + ] + } + } + }, + "definitions": { + "ObjectBlob": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "object": { + "type": "string", + "format": "byte" + } + } + }, + "ObjectDistance": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "distance": { + "type": "number", + "format": "float" + } + } + }, + "SearchConfig": { + "type": "object", + "properties": { + "num": { + "type": "integer", + "format": "int64" + }, + "radius": { + "type": "number", + "format": "float" + }, + "epsilon": { + "type": "number", + "format": "float" + }, + "timeout": { + "type": "string", + "format": "int64" + } + } + }, + "SearchObjectRequest": { + "type": "object", + "properties": { + "object": { + "type": "string", + "format": "byte" + }, + "config": { + "$ref": "#/definitions/SearchConfig" + } + } + }, + "SearchResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/definitions/ObjectDistance" + } + } + } + }, + "payloadEmpty": { + "type": "object" + }, + "protobufAny": { + "type": "object", + "properties": { + "typeUrl": { + "type": "string" + }, + "value": { + "type": "string", + "format": "byte" + } + } + }, + "runtimeError": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "runtimeStreamError": { + "type": "object", + "properties": { + "grpcCode": { + "type": "integer", + "format": "int32" + }, + "httpCode": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "httpStatus": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufAny" + } + } + } + } + } +} diff --git a/charts/vald/templates/gateway/backup/configmap.yaml b/charts/vald/templates/gateway/backup/configmap.yaml new file mode 100644 index 00000000000..74a74b27409 --- /dev/null +++ b/charts/vald/templates/gateway/backup/configmap.yaml @@ -0,0 +1,76 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.gateway.name }}-config + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +data: + config.yaml: | + --- + version: {{ .Values.gateway.version }} + time_zone: {{ default .Values.defaults.time_zone .Values.gateway.time_zone }} + logging: + {{- $logging := dict "Values" .Values.gateway.logging "default" .Values.defaults.logging }} + {{- include "vald.logging" $logging | nindent 6 }} + server_config: + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config }} + {{- include "vald.servers" $servers | nindent 6 }} + observability: + {{- $observability := dict "Values" .Values.gateway.observability "default" .Values.defaults.observability }} + {{- include "vald.observability" $observability | nindent 6 }} + gateway: + agent_port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.agent.server_config.servers.grpc.port }} + agent_name: {{ .Values.agent.name | quote }} + agent_dns: {{ .Values.agent.name }}.{{ .Release.Namespace }}.svc.cluster.local + agent_namespace: {{ .Values.gateway.gateway_config.agent_namespace | quote }} + node_name: {{ .Values.gateway.gateway_config.node_name | quote }} + index_replica: {{ .Values.gateway.gateway_config.index_replica }} + discoverer: + host: {{ .Values.discoverer.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.discoverer.server_config.servers.grpc.port }} + duration: {{ .Values.gateway.gateway_config.discoverer.duration }} + discover_client: + {{- $discoverClient := dict "Values" .Values.gateway.gateway_config.discoverer.discover_client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $discoverClient | nindent 10 }} + agent_client: + {{- $agentClient := dict "Values" .Values.gateway.gateway_config.discoverer.agent_client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $agentClient | nindent 10 }} + meta: + host: {{ .Values.meta.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.meta.server_config.servers.grpc.port }} + client: + {{- $metaClient := dict "Values" .Values.gateway.gateway_config.meta.client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $metaClient | nindent 10 }} + enable_cache: {{ .Values.gateway.gateway_config.meta.enable_cache }} + cache_expiration: {{ .Values.gateway.gateway_config.meta.cache_expiration }} + expired_cache_check_duration: {{ .Values.gateway.gateway_config.meta.expired_cache_check_duration }} + backup: + host: {{ .Values.compressor.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.compressor.server_config.servers.grpc.port }} + client: + {{- $backupClient := dict "Values" .Values.gateway.gateway_config.backup.client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $backupClient | nindent 10 }} + egress_filter: + client: null +{{- end }} diff --git a/charts/vald/templates/gateway/backup/daemonset.yaml b/charts/vald/templates/gateway/backup/daemonset.yaml new file mode 100644 index 00000000000..1b6d3428701 --- /dev/null +++ b/charts/vald/templates/gateway/backup/daemonset.yaml @@ -0,0 +1,115 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled (eq .Values.gateway.kind "DaemonSet") }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ .Values.gateway.name }} + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.annotations }} + annotations: + {{- toYaml .Values.gateway.annotations | nindent 4 }} + {{- end }} +spec: + revisionHistoryLimit: {{ .Values.gateway.revisionHistoryLimit }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} + updateStrategy: + rollingUpdate: + maxUnavailable: {{ .Values.gateway.rollingUpdate.maxUnavailable }} + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gateway + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/gateway/vald/configmap.yaml") . | sha256sum }} + {{- if .Values.gateway.podAnnotations }} + {{- toYaml .Values.gateway.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.gateway.initContainers }} + initContainers: + {{- $initContainers := dict "initContainers" .Values.gateway.initContainers "Values" .Values "namespace" .Release.Namespace -}} + {{- include "vald.initContainers" $initContainers | trim | nindent 8 }} + {{- end }} + affinity: + {{- include "vald.affinity" .Values.gateway.affinity | nindent 8 }} + topologySpreadConstraints: + {{- toYaml .Values.gateway.topologySpreadConstraints | nindent 8 }} + containers: + - name: {{ .Values.gateway.name }} + image: "{{ .Values.gateway.image.repository }}:{{ default .Values.defaults.image.tag .Values.gateway.image.tag }}" + imagePullPolicy: {{ .Values.gateway.image.pullPolicy }} + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config -}} + {{- include "vald.containerPorts" $servers | trim | nindent 10 }} + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + {{- if .Values.gateway.env }} + env: + {{- toYaml .Values.gateway.env | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Values.gateway.name }}-config + mountPath: /etc/server/ + {{- if .Values.gateway.volumeMounts }} + {{- toYaml .Values.gateway.volumeMounts | nindent 12 }} + {{- end }} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: {{ .Values.gateway.terminationGracePeriodSeconds }} + volumes: + - name: {{ .Values.gateway.name }}-config + configMap: + defaultMode: 420 + name: {{ .Values.gateway.name }}-config + {{- if .Values.gateway.volumes }} + {{- toYaml .Values.gateway.volumes | nindent 8 }} + {{- end }} + {{- if .Values.gateway.nodeName }} + nodeName: {{ .Values.gateway.nodeName }} + {{- end }} + {{- if .Values.gateway.nodeSelector }} + nodeSelector: + {{- toYaml .Values.gateway.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.gateway.tolerations }} + tolerations: + {{- toYaml .Values.gateway.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.gateway.podPriority }} + {{- if .Values.gateway.podPriority.enabled }} + priorityClassName: {{ .Values.gateway.name }}-priority + {{- end }} + {{- end }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/backup/deployment.yaml b/charts/vald/templates/gateway/backup/deployment.yaml new file mode 100644 index 00000000000..62f7fed18e5 --- /dev/null +++ b/charts/vald/templates/gateway/backup/deployment.yaml @@ -0,0 +1,120 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled (eq .Values.gateway.kind "Deployment") }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.gateway.name }} + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.annotations }} + annotations: + {{- toYaml .Values.gateway.annotations | nindent 4 }} + {{- end }} +spec: + progressDeadlineSeconds: {{ .Values.gateway.progressDeadlineSeconds }} + {{- if not .Values.gateway.hpa.enabled }} + replicas: {{ .Values.gateway.minReplicas }} + {{- end }} + revisionHistoryLimit: {{ .Values.gateway.revisionHistoryLimit }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.gateway.rollingUpdate.maxSurge }} + maxUnavailable: {{ .Values.gateway.rollingUpdate.maxUnavailable }} + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gateway + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/gateway/vald/configmap.yaml") . | sha256sum }} + {{- if .Values.gateway.podAnnotations }} + {{- toYaml .Values.gateway.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.gateway.initContainers }} + initContainers: + {{- $initContainers := dict "initContainers" .Values.gateway.initContainers "Values" .Values "namespace" .Release.Namespace -}} + {{- include "vald.initContainers" $initContainers | trim | nindent 8 }} + {{- end }} + affinity: + {{- include "vald.affinity" .Values.gateway.affinity | nindent 8 }} + topologySpreadConstraints: + {{- toYaml .Values.gateway.topologySpreadConstraints | nindent 8 }} + containers: + - name: {{ .Values.gateway.name }} + image: "{{ .Values.gateway.image.repository }}:{{ default .Values.defaults.image.tag .Values.gateway.image.tag }}" + imagePullPolicy: {{ .Values.gateway.image.pullPolicy }} + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config -}} + {{- include "vald.containerPorts" $servers | trim | nindent 10 }} + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + {{- if .Values.gateway.env }} + env: + {{- toYaml .Values.gateway.env | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Values.gateway.name }}-config + mountPath: /etc/server/ + {{- if .Values.gateway.volumeMounts }} + {{- toYaml .Values.gateway.volumeMounts | nindent 12 }} + {{- end }} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: {{ .Values.gateway.terminationGracePeriodSeconds }} + volumes: + - name: {{ .Values.gateway.name }}-config + configMap: + defaultMode: 420 + name: {{ .Values.gateway.name }}-config + {{- if .Values.gateway.volumes }} + {{- toYaml .Values.gateway.volumes | nindent 8 }} + {{- end }} + {{- if .Values.gateway.nodeName }} + nodeName: {{ .Values.gateway.nodeName }} + {{- end }} + {{- if .Values.gateway.nodeSelector }} + nodeSelector: + {{- toYaml .Values.gateway.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.gateway.tolerations }} + tolerations: + {{- toYaml .Values.gateway.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.gateway.podPriority }} + {{- if .Values.gateway.podPriority.enabled }} + priorityClassName: {{ .Values.gateway.name }}-priority + {{- end }} + {{- end }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/backup/hpa.yaml b/charts/vald/templates/gateway/backup/hpa.yaml new file mode 100644 index 00000000000..144538a892a --- /dev/null +++ b/charts/vald/templates/gateway/backup/hpa.yaml @@ -0,0 +1,37 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.hpa.enabled }} +apiVersion: autoscaling/v1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Values.gateway.name }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +spec: + maxReplicas: {{ .Values.gateway.maxReplicas }} + minReplicas: {{ .Values.gateway.minReplicas }} + scaleTargetRef: + apiVersion: apps/v1 + kind: {{ .Values.gateway.kind }} + name: {{ .Values.gateway.name }} + targetCPUUtilizationPercentage: {{ .Values.gateway.hpa.targetCPUUtilizationPercentage }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/backup/ing.yaml b/charts/vald/templates/gateway/backup/ing.yaml new file mode 100644 index 00000000000..cb113a496f4 --- /dev/null +++ b/charts/vald/templates/gateway/backup/ing.yaml @@ -0,0 +1,41 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.ingress.enabled }} +apiVersion: networking.k8s.io/v1beta1 +# apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + {{- toYaml .Values.gateway.ingress.annotations | nindent 4 }} + labels: + name: {{ .Values.gateway.name }}-ingress + app: {{ .Values.gateway.name }}-ingress + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + name: {{ .Values.gateway.name }}-ingress +spec: + rules: + - host: {{ .Values.gateway.ingress.host }} + http: + paths: + - backend: + serviceName: {{ .Values.gateway.name }} + servicePort: {{ .Values.gateway.ingress.servicePort }} +{{- end }} diff --git a/charts/vald/templates/gateway/backup/pdb.yaml b/charts/vald/templates/gateway/backup/pdb.yaml new file mode 100644 index 00000000000..7fd1c9e2232 --- /dev/null +++ b/charts/vald/templates/gateway/backup/pdb.yaml @@ -0,0 +1,33 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ .Values.gateway.name }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +spec: + maxUnavailable: {{ .Values.gateway.maxUnavailable }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} +{{- end }} diff --git a/charts/vald/templates/gateway/backup/priorityclass.yaml b/charts/vald/templates/gateway/backup/priorityclass.yaml new file mode 100644 index 00000000000..2386775dfec --- /dev/null +++ b/charts/vald/templates/gateway/backup/priorityclass.yaml @@ -0,0 +1,31 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.podPriority.enabled }} +apiVersion: scheduling.k8s.io/v1 +kind: PriorityClass +metadata: + name: {{ .Values.gateway.name }}-priority + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +value: {{ .Values.gateway.podPriority.value }} +globalDefault: false +description: "A priority class for Vald gateway." +{{- end }} diff --git a/charts/vald/templates/gateway/backup/svc.yaml b/charts/vald/templates/gateway/backup/svc.yaml new file mode 100644 index 00000000000..8cb9cbc02bc --- /dev/null +++ b/charts/vald/templates/gateway/backup/svc.yaml @@ -0,0 +1,48 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.gateway.name }} + {{- if .Values.gateway.service.annotations }} + annotations: + {{- toYaml .Values.gateway.service.annotations | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.service.labels }} + {{- toYaml .Values.gateway.service.labels | nindent 4 }} + {{- end }} +spec: + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config }} + {{- include "vald.servicePorts" $servers | nindent 2 }} + selector: + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/component: gateway + {{- if eq .Values.gateway.serviceType "ClusterIP" }} + clusterIP: None + {{- end }} + type: {{ .Values.gateway.serviceType }} + {{- if .Values.gateway.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.gateway.externalTrafficPolicy }} + {{- end }} +{{- end }} diff --git a/charts/vald/templates/gateway/filter/configmap.yaml b/charts/vald/templates/gateway/filter/configmap.yaml new file mode 100644 index 00000000000..74a74b27409 --- /dev/null +++ b/charts/vald/templates/gateway/filter/configmap.yaml @@ -0,0 +1,76 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.gateway.name }}-config + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +data: + config.yaml: | + --- + version: {{ .Values.gateway.version }} + time_zone: {{ default .Values.defaults.time_zone .Values.gateway.time_zone }} + logging: + {{- $logging := dict "Values" .Values.gateway.logging "default" .Values.defaults.logging }} + {{- include "vald.logging" $logging | nindent 6 }} + server_config: + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config }} + {{- include "vald.servers" $servers | nindent 6 }} + observability: + {{- $observability := dict "Values" .Values.gateway.observability "default" .Values.defaults.observability }} + {{- include "vald.observability" $observability | nindent 6 }} + gateway: + agent_port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.agent.server_config.servers.grpc.port }} + agent_name: {{ .Values.agent.name | quote }} + agent_dns: {{ .Values.agent.name }}.{{ .Release.Namespace }}.svc.cluster.local + agent_namespace: {{ .Values.gateway.gateway_config.agent_namespace | quote }} + node_name: {{ .Values.gateway.gateway_config.node_name | quote }} + index_replica: {{ .Values.gateway.gateway_config.index_replica }} + discoverer: + host: {{ .Values.discoverer.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.discoverer.server_config.servers.grpc.port }} + duration: {{ .Values.gateway.gateway_config.discoverer.duration }} + discover_client: + {{- $discoverClient := dict "Values" .Values.gateway.gateway_config.discoverer.discover_client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $discoverClient | nindent 10 }} + agent_client: + {{- $agentClient := dict "Values" .Values.gateway.gateway_config.discoverer.agent_client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $agentClient | nindent 10 }} + meta: + host: {{ .Values.meta.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.meta.server_config.servers.grpc.port }} + client: + {{- $metaClient := dict "Values" .Values.gateway.gateway_config.meta.client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $metaClient | nindent 10 }} + enable_cache: {{ .Values.gateway.gateway_config.meta.enable_cache }} + cache_expiration: {{ .Values.gateway.gateway_config.meta.cache_expiration }} + expired_cache_check_duration: {{ .Values.gateway.gateway_config.meta.expired_cache_check_duration }} + backup: + host: {{ .Values.compressor.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.compressor.server_config.servers.grpc.port }} + client: + {{- $backupClient := dict "Values" .Values.gateway.gateway_config.backup.client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $backupClient | nindent 10 }} + egress_filter: + client: null +{{- end }} diff --git a/charts/vald/templates/gateway/filter/daemonset.yaml b/charts/vald/templates/gateway/filter/daemonset.yaml new file mode 100644 index 00000000000..1b6d3428701 --- /dev/null +++ b/charts/vald/templates/gateway/filter/daemonset.yaml @@ -0,0 +1,115 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled (eq .Values.gateway.kind "DaemonSet") }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ .Values.gateway.name }} + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.annotations }} + annotations: + {{- toYaml .Values.gateway.annotations | nindent 4 }} + {{- end }} +spec: + revisionHistoryLimit: {{ .Values.gateway.revisionHistoryLimit }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} + updateStrategy: + rollingUpdate: + maxUnavailable: {{ .Values.gateway.rollingUpdate.maxUnavailable }} + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gateway + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/gateway/vald/configmap.yaml") . | sha256sum }} + {{- if .Values.gateway.podAnnotations }} + {{- toYaml .Values.gateway.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.gateway.initContainers }} + initContainers: + {{- $initContainers := dict "initContainers" .Values.gateway.initContainers "Values" .Values "namespace" .Release.Namespace -}} + {{- include "vald.initContainers" $initContainers | trim | nindent 8 }} + {{- end }} + affinity: + {{- include "vald.affinity" .Values.gateway.affinity | nindent 8 }} + topologySpreadConstraints: + {{- toYaml .Values.gateway.topologySpreadConstraints | nindent 8 }} + containers: + - name: {{ .Values.gateway.name }} + image: "{{ .Values.gateway.image.repository }}:{{ default .Values.defaults.image.tag .Values.gateway.image.tag }}" + imagePullPolicy: {{ .Values.gateway.image.pullPolicy }} + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config -}} + {{- include "vald.containerPorts" $servers | trim | nindent 10 }} + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + {{- if .Values.gateway.env }} + env: + {{- toYaml .Values.gateway.env | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Values.gateway.name }}-config + mountPath: /etc/server/ + {{- if .Values.gateway.volumeMounts }} + {{- toYaml .Values.gateway.volumeMounts | nindent 12 }} + {{- end }} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: {{ .Values.gateway.terminationGracePeriodSeconds }} + volumes: + - name: {{ .Values.gateway.name }}-config + configMap: + defaultMode: 420 + name: {{ .Values.gateway.name }}-config + {{- if .Values.gateway.volumes }} + {{- toYaml .Values.gateway.volumes | nindent 8 }} + {{- end }} + {{- if .Values.gateway.nodeName }} + nodeName: {{ .Values.gateway.nodeName }} + {{- end }} + {{- if .Values.gateway.nodeSelector }} + nodeSelector: + {{- toYaml .Values.gateway.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.gateway.tolerations }} + tolerations: + {{- toYaml .Values.gateway.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.gateway.podPriority }} + {{- if .Values.gateway.podPriority.enabled }} + priorityClassName: {{ .Values.gateway.name }}-priority + {{- end }} + {{- end }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/filter/deployment.yaml b/charts/vald/templates/gateway/filter/deployment.yaml new file mode 100644 index 00000000000..62f7fed18e5 --- /dev/null +++ b/charts/vald/templates/gateway/filter/deployment.yaml @@ -0,0 +1,120 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled (eq .Values.gateway.kind "Deployment") }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.gateway.name }} + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.annotations }} + annotations: + {{- toYaml .Values.gateway.annotations | nindent 4 }} + {{- end }} +spec: + progressDeadlineSeconds: {{ .Values.gateway.progressDeadlineSeconds }} + {{- if not .Values.gateway.hpa.enabled }} + replicas: {{ .Values.gateway.minReplicas }} + {{- end }} + revisionHistoryLimit: {{ .Values.gateway.revisionHistoryLimit }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.gateway.rollingUpdate.maxSurge }} + maxUnavailable: {{ .Values.gateway.rollingUpdate.maxUnavailable }} + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gateway + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/gateway/vald/configmap.yaml") . | sha256sum }} + {{- if .Values.gateway.podAnnotations }} + {{- toYaml .Values.gateway.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.gateway.initContainers }} + initContainers: + {{- $initContainers := dict "initContainers" .Values.gateway.initContainers "Values" .Values "namespace" .Release.Namespace -}} + {{- include "vald.initContainers" $initContainers | trim | nindent 8 }} + {{- end }} + affinity: + {{- include "vald.affinity" .Values.gateway.affinity | nindent 8 }} + topologySpreadConstraints: + {{- toYaml .Values.gateway.topologySpreadConstraints | nindent 8 }} + containers: + - name: {{ .Values.gateway.name }} + image: "{{ .Values.gateway.image.repository }}:{{ default .Values.defaults.image.tag .Values.gateway.image.tag }}" + imagePullPolicy: {{ .Values.gateway.image.pullPolicy }} + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config -}} + {{- include "vald.containerPorts" $servers | trim | nindent 10 }} + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + {{- if .Values.gateway.env }} + env: + {{- toYaml .Values.gateway.env | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Values.gateway.name }}-config + mountPath: /etc/server/ + {{- if .Values.gateway.volumeMounts }} + {{- toYaml .Values.gateway.volumeMounts | nindent 12 }} + {{- end }} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: {{ .Values.gateway.terminationGracePeriodSeconds }} + volumes: + - name: {{ .Values.gateway.name }}-config + configMap: + defaultMode: 420 + name: {{ .Values.gateway.name }}-config + {{- if .Values.gateway.volumes }} + {{- toYaml .Values.gateway.volumes | nindent 8 }} + {{- end }} + {{- if .Values.gateway.nodeName }} + nodeName: {{ .Values.gateway.nodeName }} + {{- end }} + {{- if .Values.gateway.nodeSelector }} + nodeSelector: + {{- toYaml .Values.gateway.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.gateway.tolerations }} + tolerations: + {{- toYaml .Values.gateway.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.gateway.podPriority }} + {{- if .Values.gateway.podPriority.enabled }} + priorityClassName: {{ .Values.gateway.name }}-priority + {{- end }} + {{- end }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/filter/hpa.yaml b/charts/vald/templates/gateway/filter/hpa.yaml new file mode 100644 index 00000000000..144538a892a --- /dev/null +++ b/charts/vald/templates/gateway/filter/hpa.yaml @@ -0,0 +1,37 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.hpa.enabled }} +apiVersion: autoscaling/v1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Values.gateway.name }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +spec: + maxReplicas: {{ .Values.gateway.maxReplicas }} + minReplicas: {{ .Values.gateway.minReplicas }} + scaleTargetRef: + apiVersion: apps/v1 + kind: {{ .Values.gateway.kind }} + name: {{ .Values.gateway.name }} + targetCPUUtilizationPercentage: {{ .Values.gateway.hpa.targetCPUUtilizationPercentage }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/filter/ing.yaml b/charts/vald/templates/gateway/filter/ing.yaml new file mode 100644 index 00000000000..cb113a496f4 --- /dev/null +++ b/charts/vald/templates/gateway/filter/ing.yaml @@ -0,0 +1,41 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.ingress.enabled }} +apiVersion: networking.k8s.io/v1beta1 +# apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + {{- toYaml .Values.gateway.ingress.annotations | nindent 4 }} + labels: + name: {{ .Values.gateway.name }}-ingress + app: {{ .Values.gateway.name }}-ingress + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + name: {{ .Values.gateway.name }}-ingress +spec: + rules: + - host: {{ .Values.gateway.ingress.host }} + http: + paths: + - backend: + serviceName: {{ .Values.gateway.name }} + servicePort: {{ .Values.gateway.ingress.servicePort }} +{{- end }} diff --git a/charts/vald/templates/gateway/filter/pdb.yaml b/charts/vald/templates/gateway/filter/pdb.yaml new file mode 100644 index 00000000000..7fd1c9e2232 --- /dev/null +++ b/charts/vald/templates/gateway/filter/pdb.yaml @@ -0,0 +1,33 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ .Values.gateway.name }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +spec: + maxUnavailable: {{ .Values.gateway.maxUnavailable }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} +{{- end }} diff --git a/charts/vald/templates/gateway/filter/priorityclass.yaml b/charts/vald/templates/gateway/filter/priorityclass.yaml new file mode 100644 index 00000000000..2386775dfec --- /dev/null +++ b/charts/vald/templates/gateway/filter/priorityclass.yaml @@ -0,0 +1,31 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.podPriority.enabled }} +apiVersion: scheduling.k8s.io/v1 +kind: PriorityClass +metadata: + name: {{ .Values.gateway.name }}-priority + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +value: {{ .Values.gateway.podPriority.value }} +globalDefault: false +description: "A priority class for Vald gateway." +{{- end }} diff --git a/charts/vald/templates/gateway/filter/svc.yaml b/charts/vald/templates/gateway/filter/svc.yaml new file mode 100644 index 00000000000..8cb9cbc02bc --- /dev/null +++ b/charts/vald/templates/gateway/filter/svc.yaml @@ -0,0 +1,48 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.gateway.name }} + {{- if .Values.gateway.service.annotations }} + annotations: + {{- toYaml .Values.gateway.service.annotations | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.service.labels }} + {{- toYaml .Values.gateway.service.labels | nindent 4 }} + {{- end }} +spec: + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config }} + {{- include "vald.servicePorts" $servers | nindent 2 }} + selector: + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/component: gateway + {{- if eq .Values.gateway.serviceType "ClusterIP" }} + clusterIP: None + {{- end }} + type: {{ .Values.gateway.serviceType }} + {{- if .Values.gateway.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.gateway.externalTrafficPolicy }} + {{- end }} +{{- end }} diff --git a/charts/vald/templates/gateway/lb/configmap.yaml b/charts/vald/templates/gateway/lb/configmap.yaml new file mode 100644 index 00000000000..74a74b27409 --- /dev/null +++ b/charts/vald/templates/gateway/lb/configmap.yaml @@ -0,0 +1,76 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.gateway.name }}-config + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +data: + config.yaml: | + --- + version: {{ .Values.gateway.version }} + time_zone: {{ default .Values.defaults.time_zone .Values.gateway.time_zone }} + logging: + {{- $logging := dict "Values" .Values.gateway.logging "default" .Values.defaults.logging }} + {{- include "vald.logging" $logging | nindent 6 }} + server_config: + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config }} + {{- include "vald.servers" $servers | nindent 6 }} + observability: + {{- $observability := dict "Values" .Values.gateway.observability "default" .Values.defaults.observability }} + {{- include "vald.observability" $observability | nindent 6 }} + gateway: + agent_port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.agent.server_config.servers.grpc.port }} + agent_name: {{ .Values.agent.name | quote }} + agent_dns: {{ .Values.agent.name }}.{{ .Release.Namespace }}.svc.cluster.local + agent_namespace: {{ .Values.gateway.gateway_config.agent_namespace | quote }} + node_name: {{ .Values.gateway.gateway_config.node_name | quote }} + index_replica: {{ .Values.gateway.gateway_config.index_replica }} + discoverer: + host: {{ .Values.discoverer.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.discoverer.server_config.servers.grpc.port }} + duration: {{ .Values.gateway.gateway_config.discoverer.duration }} + discover_client: + {{- $discoverClient := dict "Values" .Values.gateway.gateway_config.discoverer.discover_client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $discoverClient | nindent 10 }} + agent_client: + {{- $agentClient := dict "Values" .Values.gateway.gateway_config.discoverer.agent_client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $agentClient | nindent 10 }} + meta: + host: {{ .Values.meta.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.meta.server_config.servers.grpc.port }} + client: + {{- $metaClient := dict "Values" .Values.gateway.gateway_config.meta.client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $metaClient | nindent 10 }} + enable_cache: {{ .Values.gateway.gateway_config.meta.enable_cache }} + cache_expiration: {{ .Values.gateway.gateway_config.meta.cache_expiration }} + expired_cache_check_duration: {{ .Values.gateway.gateway_config.meta.expired_cache_check_duration }} + backup: + host: {{ .Values.compressor.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.compressor.server_config.servers.grpc.port }} + client: + {{- $backupClient := dict "Values" .Values.gateway.gateway_config.backup.client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $backupClient | nindent 10 }} + egress_filter: + client: null +{{- end }} diff --git a/charts/vald/templates/gateway/lb/daemonset.yaml b/charts/vald/templates/gateway/lb/daemonset.yaml new file mode 100644 index 00000000000..1b6d3428701 --- /dev/null +++ b/charts/vald/templates/gateway/lb/daemonset.yaml @@ -0,0 +1,115 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled (eq .Values.gateway.kind "DaemonSet") }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ .Values.gateway.name }} + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.annotations }} + annotations: + {{- toYaml .Values.gateway.annotations | nindent 4 }} + {{- end }} +spec: + revisionHistoryLimit: {{ .Values.gateway.revisionHistoryLimit }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} + updateStrategy: + rollingUpdate: + maxUnavailable: {{ .Values.gateway.rollingUpdate.maxUnavailable }} + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gateway + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/gateway/vald/configmap.yaml") . | sha256sum }} + {{- if .Values.gateway.podAnnotations }} + {{- toYaml .Values.gateway.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.gateway.initContainers }} + initContainers: + {{- $initContainers := dict "initContainers" .Values.gateway.initContainers "Values" .Values "namespace" .Release.Namespace -}} + {{- include "vald.initContainers" $initContainers | trim | nindent 8 }} + {{- end }} + affinity: + {{- include "vald.affinity" .Values.gateway.affinity | nindent 8 }} + topologySpreadConstraints: + {{- toYaml .Values.gateway.topologySpreadConstraints | nindent 8 }} + containers: + - name: {{ .Values.gateway.name }} + image: "{{ .Values.gateway.image.repository }}:{{ default .Values.defaults.image.tag .Values.gateway.image.tag }}" + imagePullPolicy: {{ .Values.gateway.image.pullPolicy }} + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config -}} + {{- include "vald.containerPorts" $servers | trim | nindent 10 }} + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + {{- if .Values.gateway.env }} + env: + {{- toYaml .Values.gateway.env | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Values.gateway.name }}-config + mountPath: /etc/server/ + {{- if .Values.gateway.volumeMounts }} + {{- toYaml .Values.gateway.volumeMounts | nindent 12 }} + {{- end }} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: {{ .Values.gateway.terminationGracePeriodSeconds }} + volumes: + - name: {{ .Values.gateway.name }}-config + configMap: + defaultMode: 420 + name: {{ .Values.gateway.name }}-config + {{- if .Values.gateway.volumes }} + {{- toYaml .Values.gateway.volumes | nindent 8 }} + {{- end }} + {{- if .Values.gateway.nodeName }} + nodeName: {{ .Values.gateway.nodeName }} + {{- end }} + {{- if .Values.gateway.nodeSelector }} + nodeSelector: + {{- toYaml .Values.gateway.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.gateway.tolerations }} + tolerations: + {{- toYaml .Values.gateway.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.gateway.podPriority }} + {{- if .Values.gateway.podPriority.enabled }} + priorityClassName: {{ .Values.gateway.name }}-priority + {{- end }} + {{- end }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/lb/deployment.yaml b/charts/vald/templates/gateway/lb/deployment.yaml new file mode 100644 index 00000000000..62f7fed18e5 --- /dev/null +++ b/charts/vald/templates/gateway/lb/deployment.yaml @@ -0,0 +1,120 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled (eq .Values.gateway.kind "Deployment") }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.gateway.name }} + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.annotations }} + annotations: + {{- toYaml .Values.gateway.annotations | nindent 4 }} + {{- end }} +spec: + progressDeadlineSeconds: {{ .Values.gateway.progressDeadlineSeconds }} + {{- if not .Values.gateway.hpa.enabled }} + replicas: {{ .Values.gateway.minReplicas }} + {{- end }} + revisionHistoryLimit: {{ .Values.gateway.revisionHistoryLimit }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.gateway.rollingUpdate.maxSurge }} + maxUnavailable: {{ .Values.gateway.rollingUpdate.maxUnavailable }} + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gateway + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/gateway/vald/configmap.yaml") . | sha256sum }} + {{- if .Values.gateway.podAnnotations }} + {{- toYaml .Values.gateway.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.gateway.initContainers }} + initContainers: + {{- $initContainers := dict "initContainers" .Values.gateway.initContainers "Values" .Values "namespace" .Release.Namespace -}} + {{- include "vald.initContainers" $initContainers | trim | nindent 8 }} + {{- end }} + affinity: + {{- include "vald.affinity" .Values.gateway.affinity | nindent 8 }} + topologySpreadConstraints: + {{- toYaml .Values.gateway.topologySpreadConstraints | nindent 8 }} + containers: + - name: {{ .Values.gateway.name }} + image: "{{ .Values.gateway.image.repository }}:{{ default .Values.defaults.image.tag .Values.gateway.image.tag }}" + imagePullPolicy: {{ .Values.gateway.image.pullPolicy }} + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config -}} + {{- include "vald.containerPorts" $servers | trim | nindent 10 }} + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + {{- if .Values.gateway.env }} + env: + {{- toYaml .Values.gateway.env | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Values.gateway.name }}-config + mountPath: /etc/server/ + {{- if .Values.gateway.volumeMounts }} + {{- toYaml .Values.gateway.volumeMounts | nindent 12 }} + {{- end }} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: {{ .Values.gateway.terminationGracePeriodSeconds }} + volumes: + - name: {{ .Values.gateway.name }}-config + configMap: + defaultMode: 420 + name: {{ .Values.gateway.name }}-config + {{- if .Values.gateway.volumes }} + {{- toYaml .Values.gateway.volumes | nindent 8 }} + {{- end }} + {{- if .Values.gateway.nodeName }} + nodeName: {{ .Values.gateway.nodeName }} + {{- end }} + {{- if .Values.gateway.nodeSelector }} + nodeSelector: + {{- toYaml .Values.gateway.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.gateway.tolerations }} + tolerations: + {{- toYaml .Values.gateway.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.gateway.podPriority }} + {{- if .Values.gateway.podPriority.enabled }} + priorityClassName: {{ .Values.gateway.name }}-priority + {{- end }} + {{- end }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/lb/hpa.yaml b/charts/vald/templates/gateway/lb/hpa.yaml new file mode 100644 index 00000000000..144538a892a --- /dev/null +++ b/charts/vald/templates/gateway/lb/hpa.yaml @@ -0,0 +1,37 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.hpa.enabled }} +apiVersion: autoscaling/v1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Values.gateway.name }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +spec: + maxReplicas: {{ .Values.gateway.maxReplicas }} + minReplicas: {{ .Values.gateway.minReplicas }} + scaleTargetRef: + apiVersion: apps/v1 + kind: {{ .Values.gateway.kind }} + name: {{ .Values.gateway.name }} + targetCPUUtilizationPercentage: {{ .Values.gateway.hpa.targetCPUUtilizationPercentage }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/lb/ing.yaml b/charts/vald/templates/gateway/lb/ing.yaml new file mode 100644 index 00000000000..cb113a496f4 --- /dev/null +++ b/charts/vald/templates/gateway/lb/ing.yaml @@ -0,0 +1,41 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.ingress.enabled }} +apiVersion: networking.k8s.io/v1beta1 +# apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + {{- toYaml .Values.gateway.ingress.annotations | nindent 4 }} + labels: + name: {{ .Values.gateway.name }}-ingress + app: {{ .Values.gateway.name }}-ingress + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + name: {{ .Values.gateway.name }}-ingress +spec: + rules: + - host: {{ .Values.gateway.ingress.host }} + http: + paths: + - backend: + serviceName: {{ .Values.gateway.name }} + servicePort: {{ .Values.gateway.ingress.servicePort }} +{{- end }} diff --git a/charts/vald/templates/gateway/lb/pdb.yaml b/charts/vald/templates/gateway/lb/pdb.yaml new file mode 100644 index 00000000000..7fd1c9e2232 --- /dev/null +++ b/charts/vald/templates/gateway/lb/pdb.yaml @@ -0,0 +1,33 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ .Values.gateway.name }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +spec: + maxUnavailable: {{ .Values.gateway.maxUnavailable }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} +{{- end }} diff --git a/charts/vald/templates/gateway/lb/priorityclass.yaml b/charts/vald/templates/gateway/lb/priorityclass.yaml new file mode 100644 index 00000000000..2386775dfec --- /dev/null +++ b/charts/vald/templates/gateway/lb/priorityclass.yaml @@ -0,0 +1,31 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.podPriority.enabled }} +apiVersion: scheduling.k8s.io/v1 +kind: PriorityClass +metadata: + name: {{ .Values.gateway.name }}-priority + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +value: {{ .Values.gateway.podPriority.value }} +globalDefault: false +description: "A priority class for Vald gateway." +{{- end }} diff --git a/charts/vald/templates/gateway/lb/svc.yaml b/charts/vald/templates/gateway/lb/svc.yaml new file mode 100644 index 00000000000..8cb9cbc02bc --- /dev/null +++ b/charts/vald/templates/gateway/lb/svc.yaml @@ -0,0 +1,48 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.gateway.name }} + {{- if .Values.gateway.service.annotations }} + annotations: + {{- toYaml .Values.gateway.service.annotations | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.service.labels }} + {{- toYaml .Values.gateway.service.labels | nindent 4 }} + {{- end }} +spec: + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config }} + {{- include "vald.servicePorts" $servers | nindent 2 }} + selector: + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/component: gateway + {{- if eq .Values.gateway.serviceType "ClusterIP" }} + clusterIP: None + {{- end }} + type: {{ .Values.gateway.serviceType }} + {{- if .Values.gateway.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.gateway.externalTrafficPolicy }} + {{- end }} +{{- end }} diff --git a/charts/vald/templates/gateway/meta/configmap.yaml b/charts/vald/templates/gateway/meta/configmap.yaml new file mode 100644 index 00000000000..74a74b27409 --- /dev/null +++ b/charts/vald/templates/gateway/meta/configmap.yaml @@ -0,0 +1,76 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.gateway.name }}-config + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +data: + config.yaml: | + --- + version: {{ .Values.gateway.version }} + time_zone: {{ default .Values.defaults.time_zone .Values.gateway.time_zone }} + logging: + {{- $logging := dict "Values" .Values.gateway.logging "default" .Values.defaults.logging }} + {{- include "vald.logging" $logging | nindent 6 }} + server_config: + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config }} + {{- include "vald.servers" $servers | nindent 6 }} + observability: + {{- $observability := dict "Values" .Values.gateway.observability "default" .Values.defaults.observability }} + {{- include "vald.observability" $observability | nindent 6 }} + gateway: + agent_port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.agent.server_config.servers.grpc.port }} + agent_name: {{ .Values.agent.name | quote }} + agent_dns: {{ .Values.agent.name }}.{{ .Release.Namespace }}.svc.cluster.local + agent_namespace: {{ .Values.gateway.gateway_config.agent_namespace | quote }} + node_name: {{ .Values.gateway.gateway_config.node_name | quote }} + index_replica: {{ .Values.gateway.gateway_config.index_replica }} + discoverer: + host: {{ .Values.discoverer.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.discoverer.server_config.servers.grpc.port }} + duration: {{ .Values.gateway.gateway_config.discoverer.duration }} + discover_client: + {{- $discoverClient := dict "Values" .Values.gateway.gateway_config.discoverer.discover_client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $discoverClient | nindent 10 }} + agent_client: + {{- $agentClient := dict "Values" .Values.gateway.gateway_config.discoverer.agent_client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $agentClient | nindent 10 }} + meta: + host: {{ .Values.meta.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.meta.server_config.servers.grpc.port }} + client: + {{- $metaClient := dict "Values" .Values.gateway.gateway_config.meta.client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $metaClient | nindent 10 }} + enable_cache: {{ .Values.gateway.gateway_config.meta.enable_cache }} + cache_expiration: {{ .Values.gateway.gateway_config.meta.cache_expiration }} + expired_cache_check_duration: {{ .Values.gateway.gateway_config.meta.expired_cache_check_duration }} + backup: + host: {{ .Values.compressor.name }}.{{ .Release.Namespace }}.svc.cluster.local + port: {{ default .Values.defaults.server_config.servers.grpc.port .Values.compressor.server_config.servers.grpc.port }} + client: + {{- $backupClient := dict "Values" .Values.gateway.gateway_config.backup.client "default" .Values.defaults.grpc.client }} + {{- include "vald.grpc.client" $backupClient | nindent 10 }} + egress_filter: + client: null +{{- end }} diff --git a/charts/vald/templates/gateway/meta/daemonset.yaml b/charts/vald/templates/gateway/meta/daemonset.yaml new file mode 100644 index 00000000000..1b6d3428701 --- /dev/null +++ b/charts/vald/templates/gateway/meta/daemonset.yaml @@ -0,0 +1,115 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled (eq .Values.gateway.kind "DaemonSet") }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ .Values.gateway.name }} + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.annotations }} + annotations: + {{- toYaml .Values.gateway.annotations | nindent 4 }} + {{- end }} +spec: + revisionHistoryLimit: {{ .Values.gateway.revisionHistoryLimit }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} + updateStrategy: + rollingUpdate: + maxUnavailable: {{ .Values.gateway.rollingUpdate.maxUnavailable }} + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gateway + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/gateway/vald/configmap.yaml") . | sha256sum }} + {{- if .Values.gateway.podAnnotations }} + {{- toYaml .Values.gateway.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.gateway.initContainers }} + initContainers: + {{- $initContainers := dict "initContainers" .Values.gateway.initContainers "Values" .Values "namespace" .Release.Namespace -}} + {{- include "vald.initContainers" $initContainers | trim | nindent 8 }} + {{- end }} + affinity: + {{- include "vald.affinity" .Values.gateway.affinity | nindent 8 }} + topologySpreadConstraints: + {{- toYaml .Values.gateway.topologySpreadConstraints | nindent 8 }} + containers: + - name: {{ .Values.gateway.name }} + image: "{{ .Values.gateway.image.repository }}:{{ default .Values.defaults.image.tag .Values.gateway.image.tag }}" + imagePullPolicy: {{ .Values.gateway.image.pullPolicy }} + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config -}} + {{- include "vald.containerPorts" $servers | trim | nindent 10 }} + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + {{- if .Values.gateway.env }} + env: + {{- toYaml .Values.gateway.env | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Values.gateway.name }}-config + mountPath: /etc/server/ + {{- if .Values.gateway.volumeMounts }} + {{- toYaml .Values.gateway.volumeMounts | nindent 12 }} + {{- end }} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: {{ .Values.gateway.terminationGracePeriodSeconds }} + volumes: + - name: {{ .Values.gateway.name }}-config + configMap: + defaultMode: 420 + name: {{ .Values.gateway.name }}-config + {{- if .Values.gateway.volumes }} + {{- toYaml .Values.gateway.volumes | nindent 8 }} + {{- end }} + {{- if .Values.gateway.nodeName }} + nodeName: {{ .Values.gateway.nodeName }} + {{- end }} + {{- if .Values.gateway.nodeSelector }} + nodeSelector: + {{- toYaml .Values.gateway.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.gateway.tolerations }} + tolerations: + {{- toYaml .Values.gateway.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.gateway.podPriority }} + {{- if .Values.gateway.podPriority.enabled }} + priorityClassName: {{ .Values.gateway.name }}-priority + {{- end }} + {{- end }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/meta/deployment.yaml b/charts/vald/templates/gateway/meta/deployment.yaml new file mode 100644 index 00000000000..62f7fed18e5 --- /dev/null +++ b/charts/vald/templates/gateway/meta/deployment.yaml @@ -0,0 +1,120 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled (eq .Values.gateway.kind "Deployment") }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.gateway.name }} + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.annotations }} + annotations: + {{- toYaml .Values.gateway.annotations | nindent 4 }} + {{- end }} +spec: + progressDeadlineSeconds: {{ .Values.gateway.progressDeadlineSeconds }} + {{- if not .Values.gateway.hpa.enabled }} + replicas: {{ .Values.gateway.minReplicas }} + {{- end }} + revisionHistoryLimit: {{ .Values.gateway.revisionHistoryLimit }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.gateway.rollingUpdate.maxSurge }} + maxUnavailable: {{ .Values.gateway.rollingUpdate.maxUnavailable }} + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: {{ .Values.gateway.name }} + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: gateway + annotations: + checksum/configmap: {{ include (print $.Template.BasePath "/gateway/vald/configmap.yaml") . | sha256sum }} + {{- if .Values.gateway.podAnnotations }} + {{- toYaml .Values.gateway.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.gateway.initContainers }} + initContainers: + {{- $initContainers := dict "initContainers" .Values.gateway.initContainers "Values" .Values "namespace" .Release.Namespace -}} + {{- include "vald.initContainers" $initContainers | trim | nindent 8 }} + {{- end }} + affinity: + {{- include "vald.affinity" .Values.gateway.affinity | nindent 8 }} + topologySpreadConstraints: + {{- toYaml .Values.gateway.topologySpreadConstraints | nindent 8 }} + containers: + - name: {{ .Values.gateway.name }} + image: "{{ .Values.gateway.image.repository }}:{{ default .Values.defaults.image.tag .Values.gateway.image.tag }}" + imagePullPolicy: {{ .Values.gateway.image.pullPolicy }} + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config -}} + {{- include "vald.containerPorts" $servers | trim | nindent 10 }} + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + {{- if .Values.gateway.env }} + env: + {{- toYaml .Values.gateway.env | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Values.gateway.name }}-config + mountPath: /etc/server/ + {{- if .Values.gateway.volumeMounts }} + {{- toYaml .Values.gateway.volumeMounts | nindent 12 }} + {{- end }} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: {{ .Values.gateway.terminationGracePeriodSeconds }} + volumes: + - name: {{ .Values.gateway.name }}-config + configMap: + defaultMode: 420 + name: {{ .Values.gateway.name }}-config + {{- if .Values.gateway.volumes }} + {{- toYaml .Values.gateway.volumes | nindent 8 }} + {{- end }} + {{- if .Values.gateway.nodeName }} + nodeName: {{ .Values.gateway.nodeName }} + {{- end }} + {{- if .Values.gateway.nodeSelector }} + nodeSelector: + {{- toYaml .Values.gateway.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.gateway.tolerations }} + tolerations: + {{- toYaml .Values.gateway.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.gateway.podPriority }} + {{- if .Values.gateway.podPriority.enabled }} + priorityClassName: {{ .Values.gateway.name }}-priority + {{- end }} + {{- end }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/meta/hpa.yaml b/charts/vald/templates/gateway/meta/hpa.yaml new file mode 100644 index 00000000000..144538a892a --- /dev/null +++ b/charts/vald/templates/gateway/meta/hpa.yaml @@ -0,0 +1,37 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.hpa.enabled }} +apiVersion: autoscaling/v1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Values.gateway.name }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +spec: + maxReplicas: {{ .Values.gateway.maxReplicas }} + minReplicas: {{ .Values.gateway.minReplicas }} + scaleTargetRef: + apiVersion: apps/v1 + kind: {{ .Values.gateway.kind }} + name: {{ .Values.gateway.name }} + targetCPUUtilizationPercentage: {{ .Values.gateway.hpa.targetCPUUtilizationPercentage }} +status: +{{- end }} diff --git a/charts/vald/templates/gateway/meta/ing.yaml b/charts/vald/templates/gateway/meta/ing.yaml new file mode 100644 index 00000000000..cb113a496f4 --- /dev/null +++ b/charts/vald/templates/gateway/meta/ing.yaml @@ -0,0 +1,41 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.ingress.enabled }} +apiVersion: networking.k8s.io/v1beta1 +# apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + {{- toYaml .Values.gateway.ingress.annotations | nindent 4 }} + labels: + name: {{ .Values.gateway.name }}-ingress + app: {{ .Values.gateway.name }}-ingress + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + name: {{ .Values.gateway.name }}-ingress +spec: + rules: + - host: {{ .Values.gateway.ingress.host }} + http: + paths: + - backend: + serviceName: {{ .Values.gateway.name }} + servicePort: {{ .Values.gateway.ingress.servicePort }} +{{- end }} diff --git a/charts/vald/templates/gateway/meta/pdb.yaml b/charts/vald/templates/gateway/meta/pdb.yaml new file mode 100644 index 00000000000..7fd1c9e2232 --- /dev/null +++ b/charts/vald/templates/gateway/meta/pdb.yaml @@ -0,0 +1,33 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ .Values.gateway.name }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +spec: + maxUnavailable: {{ .Values.gateway.maxUnavailable }} + selector: + matchLabels: + app: {{ .Values.gateway.name }} +{{- end }} diff --git a/charts/vald/templates/gateway/meta/priorityclass.yaml b/charts/vald/templates/gateway/meta/priorityclass.yaml new file mode 100644 index 00000000000..2386775dfec --- /dev/null +++ b/charts/vald/templates/gateway/meta/priorityclass.yaml @@ -0,0 +1,31 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if and .Values.gateway.enabled .Values.gateway.podPriority.enabled }} +apiVersion: scheduling.k8s.io/v1 +kind: PriorityClass +metadata: + name: {{ .Values.gateway.name }}-priority + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway +value: {{ .Values.gateway.podPriority.value }} +globalDefault: false +description: "A priority class for Vald gateway." +{{- end }} diff --git a/charts/vald/templates/gateway/meta/svc.yaml b/charts/vald/templates/gateway/meta/svc.yaml new file mode 100644 index 00000000000..8cb9cbc02bc --- /dev/null +++ b/charts/vald/templates/gateway/meta/svc.yaml @@ -0,0 +1,48 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +{{- if .Values.gateway.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.gateway.name }} + {{- if .Values.gateway.service.annotations }} + annotations: + {{- toYaml .Values.gateway.service.annotations | nindent 4 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ include "vald.name" . }} + helm.sh/chart: {{ include "vald.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/version: {{ .Chart.Version }} + app.kubernetes.io/component: gateway + {{- if .Values.gateway.service.labels }} + {{- toYaml .Values.gateway.service.labels | nindent 4 }} + {{- end }} +spec: + {{- $servers := dict "Values" .Values.gateway.server_config "default" .Values.defaults.server_config }} + {{- include "vald.servicePorts" $servers | nindent 2 }} + selector: + app.kubernetes.io/name: {{ include "vald.name" . }} + app.kubernetes.io/component: gateway + {{- if eq .Values.gateway.serviceType "ClusterIP" }} + clusterIP: None + {{- end }} + type: {{ .Values.gateway.serviceType }} + {{- if .Values.gateway.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.gateway.externalTrafficPolicy }} + {{- end }} +{{- end }} diff --git a/charts/vald/values.yaml b/charts/vald/values.yaml index 7baa83a0834..704afec05c8 100644 --- a/charts/vald/values.yaml +++ b/charts/vald/values.yaml @@ -752,6 +752,8 @@ agent: auto_index_length: 100 # agent.ngt.auto_save_index_duration -- duration of automatic save index auto_save_index_duration: 35m + # agent.ngt.auto_create_index_pool_size -- batch process pool size of automatic create index operation + auto_create_index_pool_size: 10000 # agent.ngt.initial_delay_max_duration -- maximum duration for initial delay initial_delay_max_duration: 3m # agent.ngt.dimension -- vector dimension diff --git a/cmd/gateway/backup/main.go b/cmd/gateway/backup/main.go new file mode 100644 index 00000000000..81c871728b3 --- /dev/null +++ b/cmd/gateway/backup/main.go @@ -0,0 +1,58 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package main provides program main +package main + +import ( + "context" + + "github.com/vdaas/vald/internal/info" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/pkg/gateway/backup/config" + "github.com/vdaas/vald/pkg/gateway/backup/usecase" +) + +const ( + maxVersion = "v0.0.10" + minVersion = "v0.0.0" + name = "gateway backup" +) + +func main() { + if err := safety.RecoverFunc(func() error { + return runner.Do( + context.Background(), + runner.WithName(name), + runner.WithVersion(info.Version, maxVersion, minVersion), + runner.WithConfigLoader(func(path string) (interface{}, *config.GlobalConfig, error) { + cfg, err := config.NewConfig(path) + if err != nil { + return nil, nil, err + } + return cfg, &cfg.GlobalConfig, nil + }), + runner.WithDaemonInitializer(func(cfg interface{}) (runner.Runner, error) { + return usecase.New(cfg.(*config.Data)) + }), + ) + })(); err != nil { + log.Fatal(err, info.Get()) + return + } +} diff --git a/cmd/gateway/backup/main_test.go b/cmd/gateway/backup/main_test.go new file mode 100644 index 00000000000..77175e62955 --- /dev/null +++ b/cmd/gateway/backup/main_test.go @@ -0,0 +1,80 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package main provides program main +package main + +import ( + "testing" + + "go.uber.org/goleak" +) + +func Test_main(t *testing.T) { + type want struct { + } + type test struct { + name string + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + main() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} diff --git a/cmd/gateway/filter/main.go b/cmd/gateway/filter/main.go new file mode 100644 index 00000000000..077f80a1365 --- /dev/null +++ b/cmd/gateway/filter/main.go @@ -0,0 +1,58 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package main provides program main +package main + +import ( + "context" + + "github.com/vdaas/vald/internal/info" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/pkg/gateway/filter/config" + "github.com/vdaas/vald/pkg/gateway/filter/usecase" +) + +const ( + maxVersion = "v0.0.10" + minVersion = "v0.0.0" + name = "gateway filter" +) + +func main() { + if err := safety.RecoverFunc(func() error { + return runner.Do( + context.Background(), + runner.WithName(name), + runner.WithVersion(info.Version, maxVersion, minVersion), + runner.WithConfigLoader(func(path string) (interface{}, *config.GlobalConfig, error) { + cfg, err := config.NewConfig(path) + if err != nil { + return nil, nil, err + } + return cfg, &cfg.GlobalConfig, nil + }), + runner.WithDaemonInitializer(func(cfg interface{}) (runner.Runner, error) { + return usecase.New(cfg.(*config.Data)) + }), + ) + })(); err != nil { + log.Fatal(err, info.Get()) + return + } +} diff --git a/cmd/gateway/filter/main_test.go b/cmd/gateway/filter/main_test.go new file mode 100644 index 00000000000..77175e62955 --- /dev/null +++ b/cmd/gateway/filter/main_test.go @@ -0,0 +1,80 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package main provides program main +package main + +import ( + "testing" + + "go.uber.org/goleak" +) + +func Test_main(t *testing.T) { + type want struct { + } + type test struct { + name string + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + main() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} diff --git a/cmd/gateway/lb/main.go b/cmd/gateway/lb/main.go new file mode 100644 index 00000000000..578848e51b4 --- /dev/null +++ b/cmd/gateway/lb/main.go @@ -0,0 +1,58 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package main provides program main +package main + +import ( + "context" + + "github.com/vdaas/vald/internal/info" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/pkg/gateway/lb/config" + "github.com/vdaas/vald/pkg/gateway/lb/usecase" +) + +const ( + maxVersion = "v0.0.10" + minVersion = "v0.0.0" + name = "gateway lb" +) + +func main() { + if err := safety.RecoverFunc(func() error { + return runner.Do( + context.Background(), + runner.WithName(name), + runner.WithVersion(info.Version, maxVersion, minVersion), + runner.WithConfigLoader(func(path string) (interface{}, *config.GlobalConfig, error) { + cfg, err := config.NewConfig(path) + if err != nil { + return nil, nil, err + } + return cfg, &cfg.GlobalConfig, nil + }), + runner.WithDaemonInitializer(func(cfg interface{}) (runner.Runner, error) { + return usecase.New(cfg.(*config.Data)) + }), + ) + })(); err != nil { + log.Fatal(err, info.Get()) + return + } +} diff --git a/cmd/gateway/lb/main_test.go b/cmd/gateway/lb/main_test.go new file mode 100644 index 00000000000..77175e62955 --- /dev/null +++ b/cmd/gateway/lb/main_test.go @@ -0,0 +1,80 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package main provides program main +package main + +import ( + "testing" + + "go.uber.org/goleak" +) + +func Test_main(t *testing.T) { + type want struct { + } + type test struct { + name string + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + main() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} diff --git a/cmd/gateway/meta/main.go b/cmd/gateway/meta/main.go new file mode 100644 index 00000000000..6e446c05886 --- /dev/null +++ b/cmd/gateway/meta/main.go @@ -0,0 +1,58 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package main provides program main +package main + +import ( + "context" + + "github.com/vdaas/vald/internal/info" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/pkg/gateway/meta/config" + "github.com/vdaas/vald/pkg/gateway/meta/usecase" +) + +const ( + maxVersion = "v0.0.10" + minVersion = "v0.0.0" + name = "gateway meta" +) + +func main() { + if err := safety.RecoverFunc(func() error { + return runner.Do( + context.Background(), + runner.WithName(name), + runner.WithVersion(info.Version, maxVersion, minVersion), + runner.WithConfigLoader(func(path string) (interface{}, *config.GlobalConfig, error) { + cfg, err := config.NewConfig(path) + if err != nil { + return nil, nil, err + } + return cfg, &cfg.GlobalConfig, nil + }), + runner.WithDaemonInitializer(func(cfg interface{}) (runner.Runner, error) { + return usecase.New(cfg.(*config.Data)) + }), + ) + })(); err != nil { + log.Fatal(err, info.Get()) + return + } +} diff --git a/cmd/gateway/meta/main_test.go b/cmd/gateway/meta/main_test.go new file mode 100644 index 00000000000..77175e62955 --- /dev/null +++ b/cmd/gateway/meta/main_test.go @@ -0,0 +1,80 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package main provides program main +package main + +import ( + "testing" + + "go.uber.org/goleak" +) + +func Test_main(t *testing.T) { + type want struct { + } + type test struct { + name string + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + main() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} diff --git a/dockers/gateway/backup/Dockerfile b/dockers/gateway/backup/Dockerfile new file mode 100644 index 00000000000..641f3018b7e --- /dev/null +++ b/dockers/gateway/backup/Dockerfile @@ -0,0 +1,80 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +FROM vdaas/vald-base:latest AS builder + +ENV ORG vdaas +ENV REPO vald +ENV PKG gateway/backup +ENV APP_NAME backup + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/internal +COPY internal . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/apis/grpc +COPY apis/grpc . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/pkg/${PKG} +COPY pkg/${PKG} . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/cmd/${PKG} +COPY cmd/${PKG} . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO} +COPY versions/GO_VERSION . +COPY versions/VALD_VERSION . +COPY .git . +RUN GO_VERSION="$(cat GO_VERSION)" \ + && VALD_VERSION="$(cat VALD_VERSION)" \ + && GIT_COMMIT="$(git rev-list -1 HEAD)" \ + && CPU_INFO_FLAGS="$(cat /proc/cpuinfo | grep flags | cut -d " " -f 2- | head -1)" \ + && GOOS="$(go env GOOS)" \ + && GOARCH="$(go env GOARCH)" \ + && CGO_ENABLED=0 \ + && GO111MODULE=on \ + go build \ + --ldflags "-s -w -linkmode 'external' \ + -extldflags '-static' \ + -X 'github.com/${ORG}/${REPO}/internal/info.Version=${VALD_VERSION}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GitCommit=${GIT_COMMIT}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoVersion=${GO_VERSION}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoOS=${GOOS}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoArch=${GOARCH}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.CGOEnabled=${CGO_ENABLED}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.BuildCPUInfoFlags=${CPU_INFO_FLAGS}'" \ + -a \ + -tags netgo \ + -installsuffix netgo \ + -trimpath \ + -o "${APP_NAME}" \ + "cmd/${PKG}/main.go" \ + && upx -9 -o "/usr/bin/${APP_NAME}" "${APP_NAME}" + +# Start From Scratch For Running Environment +FROM scratch +# Start From Alpine For Debug Environment +# FROM alpine:latest + +ENV APP_NAME backup + +# Copy certificates for SSL/TLS +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +# Copy permissions +COPY --from=builder /etc/passwd /etc/passwd +# Copy our static executable +COPY --from=builder /usr/bin/${APP_NAME} /go/bin/${APP_NAME} + +ENTRYPOINT ["/go/bin/backup"] diff --git a/dockers/gateway/filter/Dockerfile b/dockers/gateway/filter/Dockerfile new file mode 100644 index 00000000000..22f428a4d76 --- /dev/null +++ b/dockers/gateway/filter/Dockerfile @@ -0,0 +1,80 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +FROM vdaas/vald-base:latest AS builder + +ENV ORG vdaas +ENV REPO vald +ENV PKG gateway/filter +ENV APP_NAME filter + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/internal +COPY internal . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/apis/grpc +COPY apis/grpc . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/pkg/${PKG} +COPY pkg/${PKG} . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/cmd/${PKG} +COPY cmd/${PKG} . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO} +COPY versions/GO_VERSION . +COPY versions/VALD_VERSION . +COPY .git . +RUN GO_VERSION="$(cat GO_VERSION)" \ + && VALD_VERSION="$(cat VALD_VERSION)" \ + && GIT_COMMIT="$(git rev-list -1 HEAD)" \ + && CPU_INFO_FLAGS="$(cat /proc/cpuinfo | grep flags | cut -d " " -f 2- | head -1)" \ + && GOOS="$(go env GOOS)" \ + && GOARCH="$(go env GOARCH)" \ + && CGO_ENABLED=0 \ + && GO111MODULE=on \ + go build \ + --ldflags "-s -w -linkmode 'external' \ + -extldflags '-static' \ + -X 'github.com/${ORG}/${REPO}/internal/info.Version=${VALD_VERSION}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GitCommit=${GIT_COMMIT}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoVersion=${GO_VERSION}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoOS=${GOOS}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoArch=${GOARCH}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.CGOEnabled=${CGO_ENABLED}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.BuildCPUInfoFlags=${CPU_INFO_FLAGS}'" \ + -a \ + -tags netgo \ + -installsuffix netgo \ + -trimpath \ + -o "${APP_NAME}" \ + "cmd/${PKG}/main.go" \ + && upx -9 -o "/usr/bin/${APP_NAME}" "${APP_NAME}" + +# Start From Scratch For Running Environment +FROM scratch +# Start From Alpine For Debug Environment +# FROM alpine:latest + +ENV APP_NAME filter + +# Copy certificates for SSL/TLS +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +# Copy permissions +COPY --from=builder /etc/passwd /etc/passwd +# Copy our static executable +COPY --from=builder /usr/bin/${APP_NAME} /go/bin/${APP_NAME} + +ENTRYPOINT ["/go/bin/filter"] diff --git a/dockers/gateway/lb/Dockerfile b/dockers/gateway/lb/Dockerfile new file mode 100644 index 00000000000..6606f7895b4 --- /dev/null +++ b/dockers/gateway/lb/Dockerfile @@ -0,0 +1,80 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +FROM vdaas/vald-base:latest AS builder + +ENV ORG vdaas +ENV REPO vald +ENV PKG gateway/lb +ENV APP_NAME lb + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/internal +COPY internal . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/apis/grpc +COPY apis/grpc . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/pkg/${PKG} +COPY pkg/${PKG} . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/cmd/${PKG} +COPY cmd/${PKG} . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO} +COPY versions/GO_VERSION . +COPY versions/VALD_VERSION . +COPY .git . +RUN GO_VERSION="$(cat GO_VERSION)" \ + && VALD_VERSION="$(cat VALD_VERSION)" \ + && GIT_COMMIT="$(git rev-list -1 HEAD)" \ + && CPU_INFO_FLAGS="$(cat /proc/cpuinfo | grep flags | cut -d " " -f 2- | head -1)" \ + && GOOS="$(go env GOOS)" \ + && GOARCH="$(go env GOARCH)" \ + && CGO_ENABLED=0 \ + && GO111MODULE=on \ + go build \ + --ldflags "-s -w -linkmode 'external' \ + -extldflags '-static' \ + -X 'github.com/${ORG}/${REPO}/internal/info.Version=${VALD_VERSION}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GitCommit=${GIT_COMMIT}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoVersion=${GO_VERSION}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoOS=${GOOS}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoArch=${GOARCH}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.CGOEnabled=${CGO_ENABLED}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.BuildCPUInfoFlags=${CPU_INFO_FLAGS}'" \ + -a \ + -tags netgo \ + -installsuffix netgo \ + -trimpath \ + -o "${APP_NAME}" \ + "cmd/${PKG}/main.go" \ + && upx -9 -o "/usr/bin/${APP_NAME}" "${APP_NAME}" + +# Start From Scratch For Running Environment +FROM scratch +# Start From Alpine For Debug Environment +# FROM alpine:latest + +ENV APP_NAME lb + +# Copy certificates for SSL/TLS +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +# Copy permissions +COPY --from=builder /etc/passwd /etc/passwd +# Copy our static executable +COPY --from=builder /usr/bin/${APP_NAME} /go/bin/${APP_NAME} + +ENTRYPOINT ["/go/bin/lb"] diff --git a/dockers/gateway/meta/Dockerfile b/dockers/gateway/meta/Dockerfile new file mode 100644 index 00000000000..c45865750d4 --- /dev/null +++ b/dockers/gateway/meta/Dockerfile @@ -0,0 +1,80 @@ +# +# Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +FROM vdaas/vald-base:latest AS builder + +ENV ORG vdaas +ENV REPO vald +ENV PKG gateway/meta +ENV APP_NAME meta + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/internal +COPY internal . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/apis/grpc +COPY apis/grpc . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/pkg/${PKG} +COPY pkg/${PKG} . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO}/cmd/${PKG} +COPY cmd/${PKG} . + +WORKDIR ${GOPATH}/src/github.com/${ORG}/${REPO} +COPY versions/GO_VERSION . +COPY versions/VALD_VERSION . +COPY .git . +RUN GO_VERSION="$(cat GO_VERSION)" \ + && VALD_VERSION="$(cat VALD_VERSION)" \ + && GIT_COMMIT="$(git rev-list -1 HEAD)" \ + && CPU_INFO_FLAGS="$(cat /proc/cpuinfo | grep flags | cut -d " " -f 2- | head -1)" \ + && GOOS="$(go env GOOS)" \ + && GOARCH="$(go env GOARCH)" \ + && CGO_ENABLED=0 \ + && GO111MODULE=on \ + go build \ + --ldflags "-s -w -linkmode 'external' \ + -extldflags '-static' \ + -X 'github.com/${ORG}/${REPO}/internal/info.Version=${VALD_VERSION}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GitCommit=${GIT_COMMIT}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoVersion=${GO_VERSION}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoOS=${GOOS}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.GoArch=${GOARCH}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.CGOEnabled=${CGO_ENABLED}' \ + -X 'github.com/${ORG}/${REPO}/internal/info.BuildCPUInfoFlags=${CPU_INFO_FLAGS}'" \ + -a \ + -tags netgo \ + -installsuffix netgo \ + -trimpath \ + -o "${APP_NAME}" \ + "cmd/${PKG}/main.go" \ + && upx -9 -o "/usr/bin/${APP_NAME}" "${APP_NAME}" + +# Start From Scratch For Running Environment +FROM scratch +# Start From Alpine For Debug Environment +# FROM alpine:latest + +ENV APP_NAME meta + +# Copy certificates for SSL/TLS +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +# Copy permissions +COPY --from=builder /etc/passwd /etc/passwd +# Copy our static executable +COPY --from=builder /usr/bin/${APP_NAME} /go/bin/${APP_NAME} + +ENTRYPOINT ["/go/bin/meta"] diff --git a/go.mod b/go.mod index d5c33df82e5..8b8ce776687 100755 --- a/go.mod +++ b/go.mod @@ -5,29 +5,29 @@ go 1.14 replace ( github.com/Azure/go-autorest => github.com/Azure/go-autorest v14.1.1+incompatible github.com/boltdb/bolt => github.com/boltdb/bolt v1.3.1 - github.com/cockroachdb/errors => github.com/cockroachdb/errors v1.2.5-0.20200521081835-9833fdfac54c + github.com/cockroachdb/errors => github.com/cockroachdb/errors v1.2.5-0.20200526111402-489491acc692 github.com/coreos/etcd => go.etcd.io/etcd v0.5.0-alpha.5.0.20200425165423-262c93980547 github.com/docker/docker => github.com/moby/moby v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible github.com/envoyproxy/protoc-gen-validate => github.com/envoyproxy/protoc-gen-validate v0.3.0-java - github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v1.5.1-0.20200525102840-8c3a2d9049b4 - github.com/gocql/gocql => github.com/gocql/gocql v0.0.0-20200519160334-799061058e31 + github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v1.5.1-0.20200529085006-d2e52fca0b65 + github.com/gocql/gocql => github.com/gocql/gocql v0.0.0-20200526081602-cd04bd7f22a7 github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.1 github.com/gophercloud/gophercloud => github.com/gophercloud/gophercloud v0.11.0 github.com/gorilla/mux => github.com/gorilla/mux v1.7.5-0.20200517040254-948bec34b516 github.com/gorilla/websocket => github.com/gorilla/websocket v1.4.2 github.com/tensorflow/tensorflow => github.com/tensorflow/tensorflow v2.1.0+incompatible golang.org/x/crypto => golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 - k8s.io/api => k8s.io/api v0.18.2 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.18.2 - k8s.io/apimachinery => k8s.io/apimachinery v0.18.2 - k8s.io/client-go => k8s.io/client-go v0.18.2 + k8s.io/api => k8s.io/api v0.18.3 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.18.3 + k8s.io/apimachinery => k8s.io/apimachinery v0.18.3 + k8s.io/client-go => k8s.io/client-go v0.18.3 sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.6.0 ) require ( contrib.go.opencensus.io/exporter/jaeger v0.2.0 contrib.go.opencensus.io/exporter/prometheus v0.1.0 - github.com/aws/aws-sdk-go v1.31.4 + github.com/aws/aws-sdk-go v1.31.7 github.com/cespare/xxhash/v2 v2.1.1 github.com/cockroachdb/errors v0.0.0-00010101000000-000000000000 github.com/danielvladco/go-proto-gql/pb v0.6.1 @@ -59,11 +59,11 @@ require ( gocloud.dev v0.19.0 golang.org/x/mod v0.3.0 // indirect golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 - golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375 // indirect + golang.org/x/tools v0.0.0-20200530233709-52effbd89c51 // indirect gonum.org/v1/hdf5 v0.0.0-20200504100616-496fefe91614 gonum.org/v1/netlib v0.0.0-20200317120129-c5a04cffd98a // indirect gonum.org/v1/plot v0.7.0 - google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7 + google.golang.org/genproto v0.0.0-20200528191852-705c0b31589b google.golang.org/grpc v1.29.1 gopkg.in/yaml.v2 v2.3.0 k8s.io/api v0.18.3 diff --git a/go.sum b/go.sum index 245b2e78a58..db0d5080a9b 100644 --- a/go.sum +++ b/go.sum @@ -71,8 +71,8 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.31.4 h1:YZ0uEYIWeanGuAomElHmRWMAbXVqrQixxgf2vtIjO6M= -github.com/aws/aws-sdk-go v1.31.4/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.31.7 h1:TCA+pXKvzDMA3vVqhK21cCy5GarC8pTQb/DrVOWI3iY= +github.com/aws/aws-sdk-go v1.31.7/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= @@ -92,8 +92,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/errors v1.2.5-0.20200521081835-9833fdfac54c h1:SsFX20+gc2ZfxYsEe7HtlOelvynWD2e/kwi3nnfkfnc= -github.com/cockroachdb/errors v1.2.5-0.20200521081835-9833fdfac54c/go.mod h1:nbKY0iPzsFDO44PoxcY1EIGdmWBkAS6OCCKAsy/6/+w= +github.com/cockroachdb/errors v1.2.5-0.20200526111402-489491acc692 h1:VzCN+3NSfnkHDJl9rehAdTeqdJuRmwhitgB34E0CMQo= +github.com/cockroachdb/errors v1.2.5-0.20200526111402-489491acc692/go.mod h1:nbKY0iPzsFDO44PoxcY1EIGdmWBkAS6OCCKAsy/6/+w= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/cockroachdb/sentry-go v0.3.999 h1:/RJyWT8+9JyHOcm9Xf0aOd8kQkiBJAcZU3qWyzm8wkU= @@ -219,14 +219,14 @@ github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDA github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v7 v7.3.0 h1:3oHqd0W7f/VLKBxeYTEpqdMUsmMectngjM9OtoRoIgg= github.com/go-redis/redis/v7 v7.3.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= -github.com/go-sql-driver/mysql v1.5.1-0.20200525102840-8c3a2d9049b4 h1:EwVyKWAXcaG1sJdJu+D7NlZ5WZdze/plTXEBHPrf2mk= -github.com/go-sql-driver/mysql v1.5.1-0.20200525102840-8c3a2d9049b4/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.5.1-0.20200529085006-d2e52fca0b65 h1:FQnGRi70L/trwvVRnIUAJWFTjvvKHLHDCSbqW9vSTcs= +github.com/go-sql-driver/mysql v1.5.1-0.20200529085006-d2e52fca0b65/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/gocql/gocql v0.0.0-20200519160334-799061058e31 h1:j8ONZES5RCZKjrU9gxq47MnkML5gimL6bd6qtfD/Kiw= -github.com/gocql/gocql v0.0.0-20200519160334-799061058e31/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= +github.com/gocql/gocql v0.0.0-20200526081602-cd04bd7f22a7 h1:TvUE5vjfoa7fFHMlmGOk0CsauNj1w4yJjR9+/GnWVCw= +github.com/gocql/gocql v0.0.0-20200526081602-cd04bd7f22a7/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= github.com/gocraft/dbr/v2 v2.7.0 h1:x+UnhSBYPFBBdtikLSMLQ9KPuquSUj4yBijsQAhhNZo= github.com/gocraft/dbr/v2 v2.7.0/go.mod h1:wQdbxPBSloo2OlSedMxfNW0mgk0GXys9O1VFmQiwcx4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -727,8 +727,8 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191203134012-c197fd4bf371/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375 h1:SjQ2+AKWgZLc1xej6WSzL+Dfs5Uyd5xcZH1mGC411IA= -golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200530233709-52effbd89c51 h1:Wec8/IO8hAraBf0it7/dPQYOslIrgM938wZYNkLnOYc= +golang.org/x/tools v0.0.0-20200530233709-52effbd89c51/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -771,8 +771,9 @@ google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dT google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7 h1:JUs1uIDQ46c7iI0QuMPzAHqXaSmqKF0f9freFMk2ivs= -google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200528191852-705c0b31589b h1:nl5tymnV+50ACFZUDAP+xFCe3Zh3SWdMDx+ernZSKNA= +google.golang.org/genproto v0.0.0-20200528191852-705c0b31589b/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -790,8 +791,10 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -827,25 +830,23 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.18.2 h1:wG5g5ZmSVgm5B+eHMIbI9EGATS2L8Z72rda19RIEgY8= -k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/apiextensions-apiserver v0.18.2 h1:I4v3/jAuQC+89L3Z7dDgAiN4EOjN6sbm6iBqQwHTah8= -k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= -k8s.io/apimachinery v0.18.2 h1:44CmtbmkzVDAhCpRVSiP2R5PPrC2RtlIv/MoB8xpdRA= -k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= -k8s.io/client-go v0.18.2 h1:aLB0iaD4nmwh7arT2wIn+lMnAq7OswjaejkQ8p9bBYE= -k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= -k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= +k8s.io/api v0.18.3 h1:2AJaUQdgUZLoDZHrun21PW2Nx9+ll6cUzvn3IKhSIn0= +k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA= +k8s.io/apiextensions-apiserver v0.18.3 h1:h6oZO+iAgg0HjxmuNnguNdKNB9+wv3O1EBDdDWJViQ0= +k8s.io/apiextensions-apiserver v0.18.3/go.mod h1:TMsNGs7DYpMXd+8MOCX8KzPOCx8fnZMoIGB24m03+JE= +k8s.io/apimachinery v0.18.3 h1:pOGcbVAhxADgUYnjS08EFXs9QMl8qaH5U4fr5LGUrSk= +k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/apiserver v0.18.3/go.mod h1:tHQRmthRPLUtwqsOnJJMoI8SW3lnoReZeE861lH8vUw= +k8s.io/client-go v0.18.3 h1:QaJzz92tsN67oorwzmoB0a9r9ZVHuD5ryjbCKP0U22k= +k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= -k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= +k8s.io/component-base v0.18.3/go.mod h1:bp5GzGR0aGkYEfTj+eTY0AN/vXTgkJdQXjNTTVUaa3k= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/metrics v0.18.3 h1:dqseegKGBFfSoOeYagroxeW0EFrzv7zhlD9bnOdqneU= diff --git a/hack/go.mod.default b/hack/go.mod.default index a7c22727fb7..52148142e55 100755 --- a/hack/go.mod.default +++ b/hack/go.mod.default @@ -17,9 +17,9 @@ replace ( github.com/gorilla/websocket => github.com/gorilla/websocket master github.com/tensorflow/tensorflow => github.com/tensorflow/tensorflow v2.1.0 golang.org/x/crypto => golang.org/x/crypto master - k8s.io/api => k8s.io/api v0.18.2 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.18.2 - k8s.io/apimachinery => k8s.io/apimachinery v0.18.2 - k8s.io/client-go => k8s.io/client-go v0.18.2 + k8s.io/api => k8s.io/api v0.18.3 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.18.3 + k8s.io/apimachinery => k8s.io/apimachinery v0.18.3 + k8s.io/client-go => k8s.io/client-go v0.18.3 sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.6.0 ) diff --git a/internal/client/gateway/vald/grpc/client.go b/internal/client/gateway/vald/grpc/client.go index 94fdc9fd13b..099db67860c 100644 --- a/internal/client/gateway/vald/grpc/client.go +++ b/internal/client/gateway/vald/grpc/client.go @@ -23,8 +23,7 @@ import ( "github.com/vdaas/vald/apis/grpc/gateway/vald" "github.com/vdaas/vald/internal/client" "github.com/vdaas/vald/internal/config" - igrpc "github.com/vdaas/vald/internal/net/grpc" - "google.golang.org/grpc" + "github.com/vdaas/vald/internal/net/grpc" ) // Client represents gateway client interface. @@ -37,7 +36,7 @@ type Client interface { type gatewayClient struct { addr string cfg *config.GRPCClient - igrpc.Client + grpc.Client } // New returns Client implementation if no error occurs. @@ -48,7 +47,7 @@ func New(ctx context.Context, opts ...Option) (Client, error) { opt(c) } - c.Client = igrpc.New(c.cfg.Opts()...) + c.Client = grpc.New(c.cfg.Opts()...) if err := c.Client.Connect(ctx, c.addr); err != nil { return nil, err @@ -62,7 +61,7 @@ func (c *gatewayClient) Exists( req *client.ObjectID, ) (*client.ObjectID, error) { res, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).Exists(ctx, req, copts...) }, ) @@ -77,7 +76,7 @@ func (c *gatewayClient) Search( req *client.SearchRequest, ) (*client.SearchResponse, error) { res, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).Search(ctx, req, copts...) }, ) @@ -92,7 +91,7 @@ func (c *gatewayClient) SearchByID( req *client.SearchIDRequest, ) (*client.SearchResponse, error) { res, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).SearchByID(ctx, req, copts...) }, ) @@ -108,7 +107,7 @@ func (c *gatewayClient) StreamSearch( f func(*client.SearchResponse, error), ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (res interface{}, err error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (res interface{}, err error) { var st vald.Vald_StreamSearchClient st, err = vald.NewValdClient(conn).StreamSearch(ctx, copts...) @@ -135,7 +134,7 @@ func (c *gatewayClient) StreamSearchByID( f func(*client.SearchResponse, error), ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (res interface{}, err error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (res interface{}, err error) { var st vald.Vald_StreamSearchByIDClient st, err = vald.NewValdClient(conn).StreamSearchByID(ctx, copts...) @@ -161,7 +160,7 @@ func (c *gatewayClient) Insert( req *client.ObjectVector, ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).Insert(ctx, req, copts...) }, ) @@ -174,7 +173,7 @@ func (c *gatewayClient) StreamInsert( f func(error), ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (res interface{}, err error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (res interface{}, err error) { var st vald.Vald_StreamInsertClient st, err = vald.NewValdClient(conn).StreamInsert(ctx, copts...) @@ -198,7 +197,7 @@ func (c *gatewayClient) MultiInsert( req *client.ObjectVectors, ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).MultiInsert(ctx, req, copts...) }, ) @@ -210,7 +209,7 @@ func (c *gatewayClient) Update( req *client.ObjectVector, ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).Update(ctx, req, copts...) }, ) @@ -223,7 +222,7 @@ func (c *gatewayClient) StreamUpdate( f func(error), ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (res interface{}, err error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (res interface{}, err error) { var st vald.Vald_StreamUpdateClient st, err = vald.NewValdClient(conn).StreamUpdate(ctx, copts...) @@ -247,7 +246,7 @@ func (c *gatewayClient) MultiUpdate( req *client.ObjectVectors, ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).MultiUpdate(ctx, req, copts...) }, ) @@ -259,7 +258,7 @@ func (c *gatewayClient) Upsert( req *client.ObjectVector, ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).Upsert(ctx, req, copts...) }, ) @@ -271,7 +270,7 @@ func (c *gatewayClient) MultiUpsert( req *client.ObjectVectors, ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).MultiUpsert(ctx, req, copts...) }, ) @@ -284,7 +283,7 @@ func (c *gatewayClient) StreamUpsert( f func(error), ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { var st vald.Vald_StreamUpsertClient st, err := vald.NewValdClient(conn).StreamUpsert(ctx, copts...) @@ -310,7 +309,7 @@ func (c *gatewayClient) Remove( req *client.ObjectID, ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).Remove(ctx, req, copts...) }, ) @@ -323,7 +322,7 @@ func (c *gatewayClient) StreamRemove( f func(error), ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (res interface{}, err error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (res interface{}, err error) { var st vald.Vald_StreamRemoveClient st, err = vald.NewValdClient(conn).StreamRemove(ctx, copts...) @@ -346,7 +345,7 @@ func (c *gatewayClient) MultiRemove( req *client.ObjectIDs, ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).MultiRemove(ctx, req, copts...) }, ) @@ -358,7 +357,7 @@ func (c *gatewayClient) GetObject( req *client.ObjectID, ) (*client.MetaObject, error) { res, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (interface{}, error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { return vald.NewValdClient(conn).GetObject(ctx, req, copts...) }, ) @@ -374,7 +373,7 @@ func (c *gatewayClient) StreamGetObject( f func(*client.MetaObject, error), ) error { _, err := c.Client.Do(ctx, c.addr, - func(ctx context.Context, conn *igrpc.ClientConn, copts ...igrpc.CallOption) (res interface{}, err error) { + func(ctx context.Context, conn *grpc.ClientConn, copts ...grpc.CallOption) (res interface{}, err error) { var st vald.Vald_StreamGetObjectClient st, err = vald.NewValdClient(conn).StreamGetObject(ctx, copts...) @@ -382,7 +381,7 @@ func (c *gatewayClient) StreamGetObject( return nil, err } - return nil, igrpc.BidirectionalStreamClient(st, + return nil, grpc.BidirectionalStreamClient(st, func() interface{} { return dataProvider() }, func() interface{} { @@ -400,7 +399,7 @@ func streamSearch( dataProvider func() interface{}, f func(*client.SearchResponse, error), ) error { - return igrpc.BidirectionalStreamClient(st, dataProvider, + return grpc.BidirectionalStreamClient(st, dataProvider, func() interface{} { return new(client.SearchResponse) }, func(res interface{}, err error) { @@ -414,7 +413,7 @@ func stream( dataProvider func() interface{}, f func(error), ) error { - return igrpc.BidirectionalStreamClient(st, dataProvider, + return grpc.BidirectionalStreamClient(st, dataProvider, func() interface{} { return new(client.Empty) }, func(_ interface{}, err error) { diff --git a/internal/client/gateway/vald/vald.go b/internal/client/gateway/vald/vald.go new file mode 100644 index 00000000000..8cd946cde88 --- /dev/null +++ b/internal/client/gateway/vald/vald.go @@ -0,0 +1,22 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +package vald + +import "github.com/vdaas/vald/apis/grpc/gateway/vald" + +type Client interface { + vald.ValdClient +} diff --git a/internal/config/ngt.go b/internal/config/ngt.go index 5dc34c761d1..cb731575eb6 100644 --- a/internal/config/ngt.go +++ b/internal/config/ngt.go @@ -52,6 +52,9 @@ type NGT struct { // AutoIndexLength represent auto index length limit AutoIndexLength int `yaml:"auto_index_length" json:"auto_index_length"` + // AutoCreateIndexPoolSize represent the pool size for create index operation + AutoCreateIndexPoolSize uint32 `yaml:"auto_create_index_pool_size" json:"auto_create_index_pool_size"` + // InitialDelayMaxDuration represent maximum duration for initial delay InitialDelayMaxDuration string `yaml:"initial_delay_max_duration" json:"initial_delay_max_duration"` diff --git a/internal/core/ngt/ngt.go b/internal/core/ngt/ngt.go index b2964b34282..7e4289b248b 100644 --- a/internal/core/ngt/ngt.go +++ b/internal/core/ngt/ngt.go @@ -97,7 +97,7 @@ type ( // ObjectType is alias of object type in NGT type objectType int -// DistanceType is alias of distance type in NGT +// DistanceType is alias of distance type in NGTErrInvalidVector type distanceType int const ( @@ -263,6 +263,10 @@ func (n *ngt) loadObjectSpace() error { // Search returns search result as []SearchResult func (n *ngt) Search(vec []float32, size int, epsilon, radius float32) ([]SearchResult, error) { + if len(vec) != int(n.dimension) { + return nil, errors.ErrIncompatibleDimensionSize(len(vec), int(n.dimension)) + } + results := C.ngt_create_empty_results(n.ebuf) defer C.ngt_destroy_results(results) @@ -322,6 +326,10 @@ func (n *ngt) Search(vec []float32, size int, epsilon, radius float32) ([]Search // Insert returns NGT object id. // This only stores not indexing, you must call CreateIndex and SaveIndex. func (n *ngt) Insert(vec []float32) (uint, error) { + dim := int(n.dimension) + if len(vec) != dim { + return 0, errors.ErrIncompatibleDimensionSize(len(vec), dim) + } n.mu.Lock() id := C.ngt_insert_index_as_float(n.index, (*C.float)(&vec[0]), C.uint32_t(n.dimension), n.ebuf) n.mu.Unlock() @@ -359,14 +367,20 @@ func (n *ngt) BulkInsert(vecs [][]float32) ([]uint, []error) { ids := make([]uint, 0, len(vecs)) errs := make([]error, 0, len(vecs)) + dim := int(n.dimension) var id uint n.mu.Lock() for _, vec := range vecs { - // n.mu.Lock() - id = uint(C.ngt_insert_index_as_float(n.index, (*C.float)(&vec[0]), C.uint32_t(n.dimension), n.ebuf)) - // n.mu.Unlock() - if id == 0 { - errs = append(errs, n.newGoError(n.ebuf)) + id = 0 + if len(vec) != dim { + errs = append(errs, errors.ErrIncompatibleDimensionSize(len(vec), dim)) + } else { + // n.mu.Lock() + id = uint(C.ngt_insert_index_as_float(n.index, (*C.float)(&vec[0]), C.uint32_t(n.dimension), n.ebuf)) + // n.mu.Unlock() + if id == 0 { + errs = append(errs, n.newGoError(n.ebuf)) + } } ids = append(ids, id) } diff --git a/internal/core/ngt/option.go b/internal/core/ngt/option.go index b00b11efa3d..d5395bfc4a9 100644 --- a/internal/core/ngt/option.go +++ b/internal/core/ngt/option.go @@ -46,6 +46,10 @@ var ( } ) +const ( + minimumDimensionSize = 2 +) + func WithInMemoryMode(flg bool) Option { return func(n *ngt) error { n.inMemory = flg @@ -72,13 +76,17 @@ func WithBulkInsertChunkSize(size int) Option { func WithDimension(size int) Option { return func(n *ngt) error { - if size > dimensionLimit { - return errors.ErrDimensionLimitExceed(size, dimensionLimit) + + if size > dimensionLimit || size < minimumDimensionSize { + return errors.ErrInvalidDimensionSize(size, dimensionLimit) } + if C.ngt_set_property_dimension(n.prop, C.int32_t(size), n.ebuf) == ErrorCode { return errors.ErrFailedToSetDimension(n.newGoError(n.ebuf)) } + n.dimension = C.int32_t(size) + return nil } } diff --git a/internal/errors/grpc.go b/internal/errors/grpc.go index 39c0adf39d2..ab7b3dfe730 100644 --- a/internal/errors/grpc.go +++ b/internal/errors/grpc.go @@ -33,6 +33,10 @@ var ( return Errorf("invalid gRPC client connection to %s", addr) } + ErrGRPCLookupIPAddrNotFound = func(host string) error { + return Errorf("vald internal gRPC client could not find ip addrs for %s", host) + } + ErrGRPCClientNotFound = New("vald internal gRPC client not found") ErrGRPCClientConnNotFound = func(addr string) error { diff --git a/internal/errors/ngt.go b/internal/errors/ngt.go index 331e2356073..ade26fda77d 100644 --- a/internal/errors/ngt.go +++ b/internal/errors/ngt.go @@ -26,8 +26,15 @@ var ( ErrIndexNotFound = New("index file not found") - ErrDimensionLimitExceed = func(current, limit int) error { - return Errorf("supported dimension limit exceed:\trequired = %d,\tlimit = %d", current, limit) + ErrInvalidDimensionSize = func(current, limit int) error { + if limit == 0 { + return Errorf("dimension size %d is invalid, the supporting dimension size must be bigger than 2", current) + } + return Errorf("dimension size %d is invalid, the supporting dimension size must be between 2 ~ %d", current, limit) + } + + ErrIncompatibleDimensionSize = func(req, dim int) error { + return Errorf("incompatible dimension size detected\trequested: %d,\tconfigured: %d", req, dim) } ErrUnsupportedObjectType = New("unsupported ObjectType") diff --git a/internal/errors/runtime.go b/internal/errors/runtime.go index de6eafe397e..66b41747790 100644 --- a/internal/errors/runtime.go +++ b/internal/errors/runtime.go @@ -31,6 +31,6 @@ var ( } ErrRuntimeError = func(err error, r runtime.Error) error { - return Wrap(err, Errorf("system paniced caused by runtime error: %v", r).Error()) + return Wrap(err, Errorf("system panicked caused by runtime error: %v", r).Error()) } ) diff --git a/internal/net/grpc/pool/pool.go b/internal/net/grpc/pool/pool.go index f474060eaf2..3f7acbb58cc 100644 --- a/internal/net/grpc/pool/pool.go +++ b/internal/net/grpc/pool/pool.go @@ -372,6 +372,11 @@ func (p *pool) lookupIPAddr(ctx context.Context) (ips []string, err error) { log.Debugf("failed to resolve ip addr for %s \terr: %s", p.addr, err.Error()) return nil, err } + + if len(addrs) == 0 || addrs == nil { + return nil, errors.ErrGRPCLookupIPAddrNotFound(p.host) + } + ips = make([]string, 0, len(addrs)) const network = "tcp" @@ -403,6 +408,10 @@ func (p *pool) lookupIPAddr(ctx context.Context) (ips []string, err error) { ips = append(ips, ipStr) } + if len(ips) == 0 { + return nil, errors.ErrGRPCLookupIPAddrNotFound(p.host) + } + sort.Strings(ips) return ips, nil diff --git a/pkg/agent/core/ngt/service/ngt.go b/pkg/agent/core/ngt/service/ngt.go index 3b09976b0db..81af60aced1 100644 --- a/pkg/agent/core/ngt/service/ngt.go +++ b/pkg/agent/core/ngt/service/ngt.go @@ -108,6 +108,7 @@ func New(cfg *config.NGT) (nn NGT, err error) { core.WithBulkInsertChunkSize(cfg.BulkInsertChunkSize), core.WithCreationEdgeSize(cfg.CreationEdgeSize), core.WithSearchEdgeSize(cfg.SearchEdgeSize), + core.WithDefaultPoolSize(cfg.AutoCreateIndexPoolSize), } if !n.inMem && len(cfg.IndexPath) != 0 { diff --git a/pkg/agent/core/ngt/usecase/agentd.go b/pkg/agent/core/ngt/usecase/agentd.go index dae6aa483d7..fe225c84fd6 100644 --- a/pkg/agent/core/ngt/usecase/agentd.go +++ b/pkg/agent/core/ngt/usecase/agentd.go @@ -62,11 +62,9 @@ func New(cfg *config.Data) (r runner.Runner, err error) { agent.RegisterAgentServer(srv, g) }), server.WithPreStartFunc(func() error { - // TODO check unbackupped upstream return nil }), server.WithPreStopFunction(func() error { - // TODO backup all index data here return nil }), } diff --git a/pkg/gateway/backup/README.md b/pkg/gateway/backup/README.md new file mode 100755 index 00000000000..9b8d2e1af5c --- /dev/null +++ b/pkg/gateway/backup/README.md @@ -0,0 +1 @@ +# server sample diff --git a/pkg/gateway/backup/config/config.go b/pkg/gateway/backup/config/config.go new file mode 100644 index 00000000000..6e4109fdabd --- /dev/null +++ b/pkg/gateway/backup/config/config.go @@ -0,0 +1,148 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package setting stores all server application settings +package config + +import ( + "github.com/vdaas/vald/internal/config" +) + +type GlobalConfig = config.GlobalConfig + +// Config represent a application setting data content (config.yaml). +// In K8s environment, this configuration is stored in K8s ConfigMap. +type Data struct { + config.GlobalConfig `json:",inline" yaml:",inline"` + + // Server represent all server configurations + Server *config.Servers `json:"server_config" yaml:"server_config"` + + // Observability represent observability configurations + Observability *config.Observability `json:"observability" yaml:"observability"` + + // Gateway represent agent gateway service configuration + Gateway *config.Gateway `json:"gateway" yaml:"gateway"` +} + +func NewConfig(path string) (cfg *Data, err error) { + err = config.Read(path, &cfg) + + if err != nil { + return nil, err + } + + if cfg != nil { + cfg.Bind() + } + + if cfg.Server != nil { + cfg.Server = cfg.Server.Bind() + } + + if cfg.Observability != nil { + cfg.Observability = cfg.Observability.Bind() + } + + if cfg.Gateway != nil { + cfg.Gateway = cfg.Gateway.Bind() + } + + return cfg, nil +} + +// func FakeData() { +// d := Data{ +// Version: "v0.0.1", +// Server: &config.Servers{ +// Servers: []*config.Server{ +// { +// Name: "agent-rest", +// Host: "127.0.0.1", +// Port: 8080, +// Mode: "REST", +// ProbeWaitTime: "3s", +// ShutdownDuration: "5s", +// HandlerTimeout: "5s", +// IdleTimeout: "2s", +// ReadHeaderTimeout: "1s", +// ReadTimeout: "1s", +// WriteTimeout: "1s", +// }, +// { +// Name: "agent-grpc", +// Host: "127.0.0.1", +// Port: 8082, +// Mode: "GRPC", +// }, +// }, +// MetricsServers: []*config.Server{ +// { +// Name: "pprof", +// Host: "127.0.0.1", +// Port: 6060, +// Mode: "REST", +// ProbeWaitTime: "3s", +// ShutdownDuration: "5s", +// HandlerTimeout: "5s", +// IdleTimeout: "2s", +// ReadHeaderTimeout: "1s", +// ReadTimeout: "1s", +// WriteTimeout: "1s", +// }, +// }, +// HealthCheckServers: []*config.Server{ +// { +// Name: "livenesss", +// Host: "127.0.0.1", +// Port: 3000, +// }, +// { +// Name: "readiness", +// Host: "127.0.0.1", +// Port: 3001, +// }, +// }, +// StartUpStrategy: []string{ +// "livenesss", +// "pprof", +// "agent-grpc", +// "agent-rest", +// "readiness", +// }, +// ShutdownStrategy: []string{ +// "readiness", +// "agent-rest", +// "agent-grpc", +// "pprof", +// "livenesss", +// }, +// FullShutdownDuration: "30s", +// TLS: &config.TLS{ +// Enabled: false, +// Cert: "/path/to/cert", +// Key: "/path/to/key", +// CA: "/path/to/ca", +// }, +// }, +// Gateway: &config.Gateway{ +// AgentPort: 8080, +// AgentName: "vald-agent", +// BackoffEnabled: false,, +// }, +// } +// fmt.Println(config.ToRawYaml(d)) +// } diff --git a/pkg/gateway/backup/config/config_test.go b/pkg/gateway/backup/config/config_test.go new file mode 100644 index 00000000000..e8090717ead --- /dev/null +++ b/pkg/gateway/backup/config/config_test.go @@ -0,0 +1,101 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package setting stores all server application settings +package config + +import ( + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errors" + "go.uber.org/goleak" +) + +func TestNewConfig(t *testing.T) { + type args struct { + path string + } + type want struct { + wantCfg *Data + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, *Data, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCfg *Data, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCfg, w.wantCfg) { + return errors.Errorf("got = %v, want %v", gotCfg, w.wantCfg) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + path: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + path: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotCfg, err := NewConfig(test.args.path) + if err := test.checkFunc(test.want, gotCfg, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/backup/handler/doc.go b/pkg/gateway/backup/handler/doc.go new file mode 100644 index 00000000000..86b6d1869df --- /dev/null +++ b/pkg/gateway/backup/handler/doc.go @@ -0,0 +1,17 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package handler diff --git a/pkg/gateway/backup/handler/grpc/checklist.go b/pkg/gateway/backup/handler/grpc/checklist.go new file mode 100644 index 00000000000..1d3cdc4b476 --- /dev/null +++ b/pkg/gateway/backup/handler/grpc/checklist.go @@ -0,0 +1,141 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package grpc + +import ( + "sync" + "sync/atomic" + "unsafe" +) + +type checkList struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int +} + +type readOnlyCheckList struct { + m map[string]*entryCheckList + amended bool +} + +var expungedCheckList = unsafe.Pointer(new(struct{})) + +type entryCheckList struct { + p unsafe.Pointer +} + +func (m *checkList) Exists(key string) bool { + read, _ := m.read.Load().(readOnlyCheckList) + e, ok := read.m[key] + if !ok && read.amended { + m.mu.Lock() + read, _ = m.read.Load().(readOnlyCheckList) + e, ok = read.m[key] + if !ok && read.amended { + e, ok = m.dirty[key] + m.missLocked() + } + m.mu.Unlock() + } + if !ok { + return false + } + p := atomic.LoadPointer(&e.p) + if p == nil || p == expungedCheckList { + return false + } + return true +} + +func (m *checkList) Check(key string) { + value := struct{}{} + read, _ := m.read.Load().(readOnlyCheckList) + if e, ok := read.m[key]; ok && e.tryStore(&value) { + return + } + + m.mu.Lock() + read, _ = m.read.Load().(readOnlyCheckList) + if e, ok := read.m[key]; ok { + if e.unexpungeLocked() { + m.dirty[key] = e + } + atomic.StorePointer(&e.p, unsafe.Pointer(&value)) + } else if e, ok := m.dirty[key]; ok { + atomic.StorePointer(&e.p, unsafe.Pointer(&value)) + } else { + if !read.amended { + m.dirtyLocked() + m.read.Store(readOnlyCheckList{m: read.m, amended: true}) + } + m.dirty[key] = &entryCheckList{p: unsafe.Pointer(&value)} + } + m.mu.Unlock() +} + +func (e *entryCheckList) tryStore(i *struct{}) bool { + for { + p := atomic.LoadPointer(&e.p) + if p == expungedCheckList { + return false + } + if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) { + return true + } + } +} + +func (e *entryCheckList) unexpungeLocked() (wasExpunged bool) { + return atomic.CompareAndSwapPointer(&e.p, expungedCheckList, nil) +} + +func (m *checkList) missLocked() { + m.misses++ + if m.misses < len(m.dirty) { + return + } + m.read.Store(readOnlyCheckList{m: m.dirty}) + m.dirty = nil + m.misses = 0 +} + +func (m *checkList) dirtyLocked() { + if m.dirty != nil { + return + } + + read, _ := m.read.Load().(readOnlyCheckList) + m.dirty = make(map[string]*entryCheckList, len(read.m)) + for k, e := range read.m { + if !e.tryExpungeLocked() { + m.dirty[k] = e + } + } +} + +func (e *entryCheckList) tryExpungeLocked() (isExpunged bool) { + p := atomic.LoadPointer(&e.p) + for p == nil { + if atomic.CompareAndSwapPointer(&e.p, nil, expungedCheckList) { + return true + } + p = atomic.LoadPointer(&e.p) + } + return p == expungedCheckList +} diff --git a/pkg/gateway/backup/handler/grpc/checklist_test.go b/pkg/gateway/backup/handler/grpc/checklist_test.go new file mode 100644 index 00000000000..805308ea276 --- /dev/null +++ b/pkg/gateway/backup/handler/grpc/checklist_test.go @@ -0,0 +1,601 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package grpc + +import ( + "reflect" + "sync" + "sync/atomic" + "testing" + "unsafe" + + "github.com/vdaas/vald/internal/errors" +) + +func Test_checkList_Exists(t *testing.T) { + type args struct { + key string + } + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + want bool + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got bool) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + got := m.Exists(test.args.key) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_checkList_Check(t *testing.T) { + type args struct { + key string + } + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + m.Check(test.args.key) + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + +func Test_entryCheckList_tryStore(t *testing.T) { + type args struct { + i *struct{} + } + type fields struct { + p unsafe.Pointer + } + type want struct { + want bool + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got bool) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + i: struct{}{}, + }, + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + i: struct{}{}, + }, + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + e := &entryCheckList{ + p: test.fields.p, + } + + got := e.tryStore(test.args.i) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_entryCheckList_unexpungeLocked(t *testing.T) { + type fields struct { + p unsafe.Pointer + } + type want struct { + wantWasExpunged bool + } + type test struct { + name string + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want, gotWasExpunged bool) error { + if !reflect.DeepEqual(gotWasExpunged, w.wantWasExpunged) { + return errors.Errorf("got = %v, want %v", gotWasExpunged, w.wantWasExpunged) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + e := &entryCheckList{ + p: test.fields.p, + } + + gotWasExpunged := e.unexpungeLocked() + if err := test.checkFunc(test.want, gotWasExpunged); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_checkList_missLocked(t *testing.T) { + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + } + type test struct { + name string + fields fields + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + m.missLocked() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + +func Test_checkList_dirtyLocked(t *testing.T) { + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + } + type test struct { + name string + fields fields + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + m.dirtyLocked() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + +func Test_entryCheckList_tryExpungeLocked(t *testing.T) { + type fields struct { + p unsafe.Pointer + } + type want struct { + wantIsExpunged bool + } + type test struct { + name string + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want, gotIsExpunged bool) error { + if !reflect.DeepEqual(gotIsExpunged, w.wantIsExpunged) { + return errors.Errorf("got = %v, want %v", gotIsExpunged, w.wantIsExpunged) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + e := &entryCheckList{ + p: test.fields.p, + } + + gotIsExpunged := e.tryExpungeLocked() + if err := test.checkFunc(test.want, gotIsExpunged); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/backup/handler/grpc/handler.go b/pkg/gateway/backup/handler/grpc/handler.go new file mode 100644 index 00000000000..2207fb4e213 --- /dev/null +++ b/pkg/gateway/backup/handler/grpc/handler.go @@ -0,0 +1,851 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "context" + "fmt" + "math" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/kpango/fuid" + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/info" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/status" + "github.com/vdaas/vald/internal/observability/trace" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/pkg/gateway/backup/service" +) + +type server struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int +} + +func New(opts ...Option) vald.ValdServer { + s := new(server) + + for _, opt := range append(defaultOpts, opts...) { + opt(s) + } + return s +} + +func (s *server) Exists(ctx context.Context, meta *payload.Object_ID) (*payload.Object_ID, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Exists") + defer func() { + if span != nil { + span.End() + } + }() + uuid, err := s.metadata.GetUUID(ctx, meta.GetId()) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Exists API meta %s's uuid not found", meta.GetId()), err, meta.GetId(), info.Get()) + } + return &payload.Object_ID{ + Id: uuid, + }, nil +} + +func (s *server) Search(ctx context.Context, req *payload.Search_Request) (res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Search") + defer func() { + if span != nil { + span.End() + } + }() + return s.search(ctx, req.GetConfig(), + func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) { + return ac.Search(ctx, req, copts...) + }) +} + +func (s *server) SearchByID(ctx context.Context, req *payload.Search_IDRequest) ( + res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.SearchByID") + defer func() { + if span != nil { + span.End() + } + }() + metaID := req.GetId() + req.Id, err = s.metadata.GetUUID(ctx, metaID) + if err != nil { + req.Id = metaID + log.Errorf("error at SearchByID\t%v", err) + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("SearchByID API meta %s's uuid not found", metaID), err, req, info.Get()) + } + return s.search(ctx, req.GetConfig(), + func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) { + return ac.SearchByID(ctx, req, copts...) + }) +} + +func (s *server) search(ctx context.Context, cfg *payload.Search_Config, + f func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error)) ( + res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.search") + defer func() { + if span != nil { + span.End() + } + }() + maxDist := uint32(math.MaxUint32) + num := int(cfg.GetNum()) + res = new(payload.Search_Response) + res.Results = make([]*payload.Object_Distance, 0, s.gateway.GetAgentCount(ctx)*num) + dch := make(chan *payload.Object_Distance, cap(res.GetResults())/2) + eg, ectx := errgroup.New(ctx) + var cancel context.CancelFunc + var timeout time.Duration + if to := cfg.GetTimeout(); to != 0 { + timeout = time.Duration(to) + } else { + timeout = s.timeout + } + ectx, cancel = context.WithTimeout(ectx, timeout) + + eg.Go(safety.RecoverFunc(func() error { + defer cancel() + // cl := new(checkList) + visited := make(map[string]bool, len(res.Results)) + mu := sync.RWMutex{} + return s.gateway.BroadCast(ectx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + r, err := f(ctx, ac, copts...) + if err != nil { + log.Debug(err) + return nil + } + for _, dist := range r.GetResults() { + if dist.GetDistance() > math.Float32frombits(atomic.LoadUint32(&maxDist)) { + return nil + } + id := dist.GetId() + mu.RLock() + if !visited[id] { + mu.RUnlock() + mu.Lock() + visited[id] = true + mu.Unlock() + dch <- dist + } else { + mu.RUnlock() + } + // if !cl.Exists(id) { + // dch <- dist + // cl.Check(id) + // } + } + return nil + }) + })) + for { + select { + case <-ectx.Done(): + err = eg.Wait() + if err != nil { + log.Error(err) + } + close(dch) + if len(res.GetResults()) > num && num != 0 { + res.Results = res.Results[:num] + } + uuids := make([]string, 0, len(res.Results)) + for _, r := range res.Results { + uuids = append(uuids, r.GetId()) + } + if s.metadata != nil { + metas, merr := s.metadata.GetMetas(ctx, uuids...) + if merr != nil { + log.Error(merr) + err = errors.Wrap(err, merr.Error()) + } + for i, k := range metas { + if len(k) != 0 { + res.Results[i].Id = k + } + } + } + if s.filter != nil { + r, ferr := s.filter.FilterSearch(ctx, res) + if ferr == nil { + res = r + } else { + err = errors.Wrap(err, ferr.Error()) + } + } + if err != nil { + return res, status.WrapWithInternal(fmt.Sprintf("failed to search request %#v", cfg), err, info.Get()) + } + return res, nil + case dist := <-dch: + if len(res.GetResults()) >= num && + dist.GetDistance() < math.Float32frombits(atomic.LoadUint32(&maxDist)) { + atomic.StoreUint32(&maxDist, math.Float32bits(dist.GetDistance())) + } + switch len(res.GetResults()) { + case 0: + res.Results = append(res.Results, dist) + continue + case 1: + if res.GetResults()[0].GetDistance() <= dist.GetDistance() { + res.Results = append(res.Results, dist) + } else { + res.Results = append([]*payload.Object_Distance{dist}, res.Results[0]) + } + continue + } + + pos := len(res.GetResults()) + for idx := pos; idx >= 1; idx-- { + if res.GetResults()[idx-1].GetDistance() <= dist.GetDistance() { + pos = idx - 1 + break + } + } + switch { + case pos == len(res.GetResults()): + res.Results = append([]*payload.Object_Distance{dist}, res.Results...) + case pos == len(res.GetResults())-1: + res.Results = append(res.GetResults(), dist) + case pos >= 0: + res.Results = append(res.GetResults()[:pos+1], res.GetResults()[pos:]...) + res.Results[pos+1] = dist + } + if len(res.GetResults()) > num && num != 0 { + res.Results = res.GetResults()[:num] + } + } + } +} + +func (s *server) StreamSearch(stream vald.Vald_StreamSearchServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamSearch") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Search_Request) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Search(ctx, data.(*payload.Search_Request)) + }) +} + +func (s *server) StreamSearchByID(stream vald.Vald_StreamSearchByIDServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamSearchByID") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Search_IDRequest) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.SearchByID(ctx, data.(*payload.Search_IDRequest)) + }) +} + +func (s *server) Insert(ctx context.Context, vec *payload.Object_Vector) (ce *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Insert") + defer func() { + if span != nil { + span.End() + } + }() + meta := vec.GetId() + exists, err := s.metadata.Exists(ctx, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal( + fmt.Sprintf("Insert API meta %s couldn't check meta already exists or not", meta), err, info.Get()) + } + if exists { + err = errors.Wrap(err, errors.ErrMetaDataAlreadyExists(meta).Error()) + if span != nil { + span.SetStatus(trace.StatusCodeAlreadyExists(err.Error())) + } + return nil, status.WrapWithAlreadyExists(fmt.Sprintf("Insert API meta %s already exists", meta), err, info.Get()) + } + + uuid := fuid.String() + err = s.metadata.SetUUIDandMeta(ctx, uuid, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Insert API meta %s & uuid %s couldn't store", meta, uuid), err, info.Get()) + } + vec.Id = uuid + mu := new(sync.Mutex) + targets := make([]string, 0, s.replica) + err = s.gateway.DoMulti(ctx, s.replica, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) (err error) { + _, err = ac.Insert(ctx, vec, copts...) + if err != nil { + if err == errors.ErrRPCCallFailed(target, context.Canceled) { + return nil + } + return err + } + target = strings.SplitN(target, ":", 2)[0] + mu.Lock() + targets = append(targets, target) + mu.Unlock() + return nil + }) + if err != nil { + err = errors.Wrapf(err, "Insert API (do multiple) failed to Insert uuid = %s\tmeta = %s\t info = %#v", uuid, meta, info.Get()) + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Insert API failed to Execute DoMulti error = %s", err.Error()), err, info.Get()) + } + if s.backup != nil { + vecs := &payload.Backup_MetaVector{ + Uuid: uuid, + Meta: meta, + Ips: targets, + } + if vec != nil { + vecs.Vector = vec.GetVector() + } + err = s.backup.Register(ctx, vecs) + if err != nil { + err = errors.Wrapf(err, "Insert API (backup.Register) failed to Backup Vectors = %#v\t info = %#v", vecs, info.Get()) + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(err.Error(), err) + } + } + log.Debugf("Insert API insert succeeded to %v", targets) + return new(payload.Empty), nil +} + +func (s *server) StreamInsert(stream vald.Vald_StreamInsertServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamInsert") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Insert(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiInsert(ctx context.Context, vecs *payload.Object_Vectors) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiInsert") + defer func() { + if span != nil { + span.End() + } + }() + metaMap := make(map[string]string) + metas := make([]string, 0, len(vecs.GetVectors())) + for i, vec := range vecs.GetVectors() { + uuid := fuid.String() + meta := vec.GetId() + metaMap[uuid] = meta + metas = append(metas, meta) + vecs.Vectors[i].Id = uuid + } + + for _, meta := range metas { + exists, err := s.metadata.Exists(ctx, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal( + fmt.Sprintf("MultiInsert API couldn't check metadata exists or not metas = %v", metas), err, info.Get()) + } + if exists { + if span != nil { + span.SetStatus(trace.StatusCodeAlreadyExists(err.Error())) + } + return nil, status.WrapWithAlreadyExists( + fmt.Sprintf("MultiInsert API failed metadata already exists meta = %s", meta), err, info.Get()) + } + } + + err = s.metadata.SetUUIDandMetas(ctx, metaMap) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed SetUUIDandMetas %#v", metaMap), err, info.Get()) + } + + mu := new(sync.Mutex) + targets := make([]string, 0, s.replica) + gerr := s.gateway.DoMulti(ctx, s.replica, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) (err error) { + _, err = ac.MultiInsert(ctx, vecs, copts...) + if err != nil { + return err + } + target = strings.SplitN(target, ":", 2)[0] + mu.Lock() + targets = append(targets, target) + mu.Unlock() + return nil + }) + if gerr != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed request %#v", vecs), errors.Wrap(gerr, err.Error()), info.Get()) + } + + if s.backup != nil { + mvecs := new(payload.Backup_MetaVectors) + mvecs.Vectors = make([]*payload.Backup_MetaVector, 0, len(vecs.GetVectors())) + for _, vec := range vecs.GetVectors() { + uuid := vec.GetId() + mvecs.Vectors = append(mvecs.Vectors, &payload.Backup_MetaVector{ + Uuid: uuid, + Meta: metaMap[uuid], + Vector: vec.GetVector(), + Ips: targets, + }) + } + err = s.backup.RegisterMultiple(ctx, mvecs) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed RegisterMultiple %#v", mvecs), err, info.Get()) + } + } + return new(payload.Empty), nil +} + +func (s *server) Update(ctx context.Context, vec *payload.Object_Vector) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Update") + defer func() { + if span != nil { + span.End() + } + }() + meta := vec.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Update API failed GetUUID meta = %s", meta), err, info.Get()) + } + vec.Id = uuid + locs, err := s.backup.GetLocation(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Update API failed GetLocation meta = %s, uuid = %s", meta, uuid), err, info.Get()) + } + lmap := make(map[string]struct{}, len(locs)) + for _, loc := range locs { + lmap[loc] = struct{}{} + } + err = s.gateway.BroadCast(ctx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + target = strings.SplitN(target, ":", 2)[0] + _, ok := lmap[target] + if ok { + _, err = ac.Update(ctx, vec, copts...) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Update API failed request %#v", vec), err, info.Get()) + } + mvec := &payload.Backup_MetaVector{ + Uuid: uuid, + Meta: meta, + Vector: vec.GetVector(), + Ips: locs, + } + err = s.backup.Register(ctx, mvec) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Update API failed backup %#v", vec), err, info.Get()) + } + + return new(payload.Empty), nil +} + +func (s *server) StreamUpdate(stream vald.Vald_StreamUpdateServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamUpdate") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Update(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiUpdate(ctx context.Context, vecs *payload.Object_Vectors) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiUpdate") + defer func() { + if span != nil { + span.End() + } + }() + ids := make([]string, 0, len(vecs.GetVectors())) + for _, vec := range vecs.GetVectors() { + ids = append(ids, vec.GetId()) + } + _, err = s.MultiRemove(ctx, &payload.Object_IDs{ + Ids: ids, + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiUpdate API failed Remove request %#v", ids), err, info.Get()) + } + _, err = s.MultiInsert(ctx, vecs) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiUpdate API failed Insert request %#v", vecs), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) Upsert(ctx context.Context, vec *payload.Object_Vector) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Upsert") + defer func() { + if span != nil { + span.End() + } + }() + + meta := vec.GetId() + exists, errs := s.metadata.Exists(ctx, meta) + if errs != nil { + log.Error(errs) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(errs.Error())) + } + } + + if exists { + _, err := s.Update(ctx, vec) + if err != nil { + errs = errors.Wrap(errs, err.Error()) + } + } else { + _, err := s.Insert(ctx, vec) + if err != nil { + errs = errors.Wrap(errs, err.Error()) + } + } + + return new(payload.Empty), errs +} + +func (s *server) StreamUpsert(stream vald.Vald_StreamUpsertServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamUpsert") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Upsert(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiUpsert(ctx context.Context, vecs *payload.Object_Vectors) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiUpsert") + defer func() { + if span != nil { + span.End() + } + }() + + insertVecs := make([]*payload.Object_Vector, 0, len(vecs.GetVectors())) + updateVecs := make([]*payload.Object_Vector, 0, len(vecs.GetVectors())) + + var errs error + for _, vec := range vecs.GetVectors() { + exists, err := s.metadata.Exists(ctx, vec.GetId()) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + errs = errors.Wrap(errs, err.Error()) + } + + if exists { + updateVecs = append(updateVecs, vec) + } else { + insertVecs = append(insertVecs, vec) + } + } + + eg, ectx := errgroup.New(ctx) + + eg.Go(safety.RecoverFunc(func() error { + var err error + if len(updateVecs) > 0 { + _, err = s.MultiUpdate(ectx, &payload.Object_Vectors{ + Vectors: updateVecs, + }) + } + return err + })) + + eg.Go(safety.RecoverFunc(func() error { + var err error + if len(insertVecs) > 0 { + _, err = s.MultiInsert(ectx, &payload.Object_Vectors{ + Vectors: insertVecs, + }) + } + return err + })) + + err := eg.Wait() + if err != nil { + errs = errors.Wrap(errs, err.Error()) + return nil, status.WrapWithInternal("MultiUpsert API failed", errs, info.Get()) + } + + return new(payload.Empty), errs +} + +func (s *server) Remove(ctx context.Context, id *payload.Object_ID) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Remove") + defer func() { + if span != nil { + span.End() + } + }() + meta := id.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Remove API meta %s's uuid not found", meta), err, info.Get()) + } + locs, err := s.backup.GetLocation(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Remove API failed GetLocation meta = %s, uuid = %s", meta, uuid), err, info.Get()) + } + lmap := make(map[string]struct{}, len(locs)) + for _, loc := range locs { + lmap[loc] = struct{}{} + } + err = s.gateway.BroadCast(ctx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + _, ok := lmap[target] + if ok { + _, err = ac.Remove(ctx, &payload.Object_ID{ + Id: uuid, + }, copts...) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed request uuid %s", uuid), err, info.Get()) + } + _, err = s.metadata.DeleteMeta(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed Delete metadata uuid = %s", uuid), err, info.Get()) + } + err = s.backup.Remove(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed to Remove backup uuid = %s", uuid), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) StreamRemove(stream vald.Vald_StreamRemoveServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamRemove") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_ID) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Remove(ctx, data.(*payload.Object_ID)) + }) +} + +func (s *server) MultiRemove(ctx context.Context, ids *payload.Object_IDs) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiRemove") + defer func() { + if span != nil { + span.End() + } + }() + uuids, err := s.metadata.GetUUIDs(ctx, ids.GetIds()...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("MultiRemove API meta datas %v's uuid not found", ids.GetIds()), err, info.Get()) + } + lmap := make(map[string][]string, s.gateway.GetAgentCount(ctx)) + for _, uuid := range uuids { + locs, err := s.backup.GetLocation(ctx, uuid) + if err != nil { + return nil, status.WrapWithNotFound(fmt.Sprintf("MultiRemove API failed to get uuid %s's location ", uuid), err, info.Get()) + } + for _, loc := range locs { + lmap[loc] = append(lmap[loc], uuid) + } + } + err = s.gateway.BroadCast(ctx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + uuids, ok := lmap[target] + if ok { + _, err := ac.MultiRemove(ctx, &payload.Object_IDs{ + Ids: uuids, + }, copts...) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to request uuids %v metas %v ", uuids, ids.GetIds()), err, info.Get()) + } + _, err = s.metadata.DeleteMetas(ctx, uuids...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to DeleteMetas uuids %v ", uuids), err, info.Get()) + } + err = s.backup.RemoveMultiple(ctx, uuids...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to Remove backup uuids %v ", uuids), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) GetObject(ctx context.Context, id *payload.Object_ID) (vec *payload.Backup_MetaVector, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.GetObject") + defer func() { + if span != nil { + span.End() + } + }() + meta := id.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("GetObject API meta %s's uuid not found", meta), err, info.Get()) + } + vec, err = s.backup.GetObject(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("GetObject API meta %s uuid %s Object not found", meta, uuid), err, info.Get()) + } + return vec, nil +} + +func (s *server) StreamGetObject(stream vald.Vald_StreamGetObjectServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamGetObject") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_ID) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.GetObject(ctx, data.(*payload.Object_ID)) + }) +} diff --git a/pkg/gateway/backup/handler/grpc/handler_test.go b/pkg/gateway/backup/handler/grpc/handler_test.go new file mode 100644 index 00000000000..3e8d0aa633b --- /dev/null +++ b/pkg/gateway/backup/handler/grpc/handler_test.go @@ -0,0 +1,2440 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "context" + "reflect" + "testing" + "time" + + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/pkg/gateway/backup/service" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want vald.ValdServer + } + type test struct { + name string + args args + want want + checkFunc func(want, vald.ValdServer) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got vald.ValdServer) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Exists(t *testing.T) { + type args struct { + ctx context.Context + meta *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Object_ID + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Object_ID, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Object_ID, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Exists(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Search(t *testing.T) { + type args struct { + ctx context.Context + req *payload.Search_Request + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.Search(test.args.ctx, test.args.req) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_SearchByID(t *testing.T) { + type args struct { + ctx context.Context + req *payload.Search_IDRequest + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.SearchByID(test.args.ctx, test.args.req) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_search(t *testing.T) { + type args struct { + ctx context.Context + cfg *payload.Search_Config + f func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + cfg: nil, + f: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + cfg: nil, + f: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.search(test.args.ctx, test.args.cfg, test.args.f) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamSearch(t *testing.T) { + type args struct { + stream vald.Vald_StreamSearchServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamSearch(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamSearchByID(t *testing.T) { + type args struct { + stream vald.Vald_StreamSearchByIDServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamSearchByID(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Insert(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantCe *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCe *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCe, w.wantCe) { + return errors.Errorf("got = %v, want %v", gotCe, w.wantCe) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotCe, err := s.Insert(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, gotCe, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamInsert(t *testing.T) { + type args struct { + stream vald.Vald_StreamInsertServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamInsert(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiInsert(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiInsert(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Update(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.Update(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamUpdate(t *testing.T) { + type args struct { + stream vald.Vald_StreamUpdateServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamUpdate(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiUpdate(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiUpdate(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Upsert(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Upsert(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamUpsert(t *testing.T) { + type args struct { + stream vald.Vald_StreamUpsertServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamUpsert(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiUpsert(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.MultiUpsert(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Remove(t *testing.T) { + type args struct { + ctx context.Context + id *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Remove(test.args.ctx, test.args.id) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamRemove(t *testing.T) { + type args struct { + stream vald.Vald_StreamRemoveServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamRemove(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiRemove(t *testing.T) { + type args struct { + ctx context.Context + ids *payload.Object_IDs + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + ids: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + ids: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiRemove(test.args.ctx, test.args.ids) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_GetObject(t *testing.T) { + type args struct { + ctx context.Context + id *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantVec *payload.Backup_MetaVector + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Backup_MetaVector, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotVec *payload.Backup_MetaVector, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotVec, w.wantVec) { + return errors.Errorf("got = %v, want %v", gotVec, w.wantVec) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotVec, err := s.GetObject(test.args.ctx, test.args.id) + if err := test.checkFunc(test.want, gotVec, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamGetObject(t *testing.T) { + type args struct { + stream vald.Vald_StreamGetObjectServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamGetObject(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/backup/handler/grpc/option.go b/pkg/gateway/backup/handler/grpc/option.go new file mode 100644 index 00000000000..fe208ee5b32 --- /dev/null +++ b/pkg/gateway/backup/handler/grpc/option.go @@ -0,0 +1,103 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "time" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/timeutil" + "github.com/vdaas/vald/pkg/gateway/backup/service" +) + +type Option func(*server) + +var ( + defaultOpts = []Option{ + WithErrGroup(errgroup.Get()), + WithReplicationCount(3), + WithStreamConcurrency(20), + WithTimeout("5s"), + } +) + +func WithGateway(g service.Gateway) Option { + return func(s *server) { + if g != nil { + s.gateway = g + } + } +} + +func WithMeta(m service.Meta) Option { + return func(s *server) { + if m != nil { + s.metadata = m + } + } +} + +func WithBackup(b service.Backup) Option { + return func(s *server) { + if b != nil { + s.backup = b + } + } +} + +func WithFilters(filter service.Filter) Option { + return func(s *server) { + if filter != nil { + s.filter = filter + } + } +} + +func WithErrGroup(eg errgroup.Group) Option { + return func(s *server) { + if eg != nil { + s.eg = eg + } + } +} + +func WithTimeout(dur string) Option { + return func(s *server) { + d, err := timeutil.Parse(dur) + if err != nil { + d = time.Second * 10 + } + s.timeout = d + } +} + +func WithReplicationCount(rep int) Option { + return func(s *server) { + if rep > 1 { + s.replica = rep + } + } +} + +func WithStreamConcurrency(c int) Option { + return func(s *server) { + if c != 0 { + s.streamConcurrency = c + } + } +} diff --git a/pkg/gateway/backup/handler/grpc/option_test.go b/pkg/gateway/backup/handler/grpc/option_test.go new file mode 100644 index 00000000000..cd1ed07d4c8 --- /dev/null +++ b/pkg/gateway/backup/handler/grpc/option_test.go @@ -0,0 +1,931 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "testing" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/pkg/gateway/backup/service" + + "go.uber.org/goleak" +) + +func TestWithGateway(t *testing.T) { + type T = interface{} + type args struct { + g service.Gateway + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + g: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + g: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithGateway(test.args.g) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithGateway(test.args.g) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMeta(t *testing.T) { + type T = interface{} + type args struct { + m service.Meta + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + m: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + m: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMeta(test.args.m) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMeta(test.args.m) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithBackup(t *testing.T) { + type T = interface{} + type args struct { + b service.Backup + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + b: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + b: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackup(test.args.b) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackup(test.args.b) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithFilters(t *testing.T) { + type T = interface{} + type args struct { + filter service.Filter + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + filter: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + filter: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithFilters(test.args.filter) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithFilters(test.args.filter) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithErrGroup(t *testing.T) { + type T = interface{} + type args struct { + eg errgroup.Group + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithErrGroup(test.args.eg) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithErrGroup(test.args.eg) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithTimeout(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithTimeout(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithTimeout(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithReplicationCount(t *testing.T) { + type T = interface{} + type args struct { + rep int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + rep: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + rep: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithReplicationCount(test.args.rep) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithReplicationCount(test.args.rep) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithStreamConcurrency(t *testing.T) { + type T = interface{} + type args struct { + c int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + c: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + c: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithStreamConcurrency(test.args.c) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithStreamConcurrency(test.args.c) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/backup/handler/rest/handler.go b/pkg/gateway/backup/handler/rest/handler.go new file mode 100644 index 00000000000..c9b9b962660 --- /dev/null +++ b/pkg/gateway/backup/handler/rest/handler.go @@ -0,0 +1,131 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "net/http" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/net/http/dump" + "github.com/vdaas/vald/internal/net/http/json" +) + +type Handler interface { + Index(w http.ResponseWriter, r *http.Request) (int, error) + Exists(w http.ResponseWriter, r *http.Request) (int, error) + Search(w http.ResponseWriter, r *http.Request) (int, error) + SearchByID(w http.ResponseWriter, r *http.Request) (int, error) + Insert(w http.ResponseWriter, r *http.Request) (int, error) + MultiInsert(w http.ResponseWriter, r *http.Request) (int, error) + Update(w http.ResponseWriter, r *http.Request) (int, error) + MultiUpdate(w http.ResponseWriter, r *http.Request) (int, error) + Remove(w http.ResponseWriter, r *http.Request) (int, error) + MultiRemove(w http.ResponseWriter, r *http.Request) (int, error) + GetObject(w http.ResponseWriter, r *http.Request) (int, error) +} + +type handler struct { + vald vald.ValdServer +} + +func New(opts ...Option) Handler { + h := new(handler) + + for _, opt := range append(defaultOpts, opts...) { + opt(h) + } + return h +} + +func (h *handler) Index(w http.ResponseWriter, r *http.Request) (int, error) { + data := make(map[string]interface{}) + return json.Handler(w, r, &data, func() (interface{}, error) { + return dump.Request(nil, data, r) + }) +} + +func (h *handler) Search(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Search_Request + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Search(r.Context(), req) + }) +} + +func (h *handler) SearchByID(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Search_IDRequest + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.SearchByID(r.Context(), req) + }) +} + +func (h *handler) Insert(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vector + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Insert(r.Context(), req) + }) +} + +func (h *handler) MultiInsert(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vectors + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiInsert(r.Context(), req) + }) +} + +func (h *handler) Update(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vector + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Update(r.Context(), req) + }) +} + +func (h *handler) MultiUpdate(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vectors + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiUpdate(r.Context(), req) + }) +} + +func (h *handler) Remove(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Remove(r.Context(), req) + }) +} + +func (h *handler) MultiRemove(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_IDs + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiRemove(r.Context(), req) + }) +} + +func (h *handler) GetObject(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.GetObject(r.Context(), req) + }) +} + +func (h *handler) Exists(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Exists(r.Context(), req) + }) +} diff --git a/pkg/gateway/backup/handler/rest/handler_test.go b/pkg/gateway/backup/handler/rest/handler_test.go new file mode 100644 index 00000000000..37fee9c24f7 --- /dev/null +++ b/pkg/gateway/backup/handler/rest/handler_test.go @@ -0,0 +1,1101 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "net/http" + "reflect" + "testing" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/internal/errors" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want Handler + } + type test struct { + name string + args args + want want + checkFunc func(want, Handler) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got Handler) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Index(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + want int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + got, err := h.Index(test.args.w, test.args.r) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Search(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Search(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_SearchByID(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.SearchByID(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Insert(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Insert(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiInsert(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiInsert(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Update(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Update(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiUpdate(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiUpdate(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Remove(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Remove(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiRemove(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiRemove(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_GetObject(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.GetObject(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Exists(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Exists(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/backup/handler/rest/option.go b/pkg/gateway/backup/handler/rest/option.go new file mode 100644 index 00000000000..c684ad7ec83 --- /dev/null +++ b/pkg/gateway/backup/handler/rest/option.go @@ -0,0 +1,32 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import "github.com/vdaas/vald/apis/grpc/gateway/vald" + +type Option func(*handler) + +var ( + defaultOpts = []Option{} +) + +func WithVald(v vald.ValdServer) Option { + return func(h *handler) { + h.vald = v + } +} diff --git a/pkg/gateway/backup/handler/rest/option_test.go b/pkg/gateway/backup/handler/rest/option_test.go new file mode 100644 index 00000000000..3f900a77c5c --- /dev/null +++ b/pkg/gateway/backup/handler/rest/option_test.go @@ -0,0 +1,139 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "testing" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + + "go.uber.org/goleak" +) + +func TestWithVald(t *testing.T) { + type T = interface{} + type args struct { + v vald.ValdServer + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + v: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + v: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithVald(test.args.v) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithVald(test.args.v) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/backup/router/option.go b/pkg/gateway/backup/router/option.go new file mode 100644 index 00000000000..b993e7c92f9 --- /dev/null +++ b/pkg/gateway/backup/router/option.go @@ -0,0 +1,42 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "github.com/vdaas/vald/pkg/gateway/backup/handler/rest" +) + +type Option func(*router) + +var ( + defaultOpts = []Option{ + WithTimeout("3s"), + } +) + +func WithHandler(h rest.Handler) Option { + return func(r *router) { + r.handler = h + } +} + +func WithTimeout(timeout string) Option { + return func(r *router) { + r.timeout = timeout + } +} diff --git a/pkg/gateway/backup/router/option_test.go b/pkg/gateway/backup/router/option_test.go new file mode 100644 index 00000000000..d98195e45cb --- /dev/null +++ b/pkg/gateway/backup/router/option_test.go @@ -0,0 +1,252 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "testing" + + "github.com/vdaas/vald/pkg/gateway/backup/handler/rest" + + "go.uber.org/goleak" +) + +func TestWithHandler(t *testing.T) { + type T = interface{} + type args struct { + h rest.Handler + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + h: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + h: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithHandler(test.args.h) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithHandler(test.args.h) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithTimeout(t *testing.T) { + type T = interface{} + type args struct { + timeout string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + timeout: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + timeout: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithTimeout(test.args.timeout) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithTimeout(test.args.timeout) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/backup/router/router.go b/pkg/gateway/backup/router/router.go new file mode 100644 index 00000000000..ad57df8d7cf --- /dev/null +++ b/pkg/gateway/backup/router/router.go @@ -0,0 +1,130 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "net/http" + + "github.com/vdaas/vald/internal/net/http/routing" + "github.com/vdaas/vald/pkg/gateway/backup/handler/rest" +) + +type router struct { + handler rest.Handler + timeout string +} + +// New returns REST route&method information from handler interface +func New(opts ...Option) http.Handler { + r := new(router) + + for _, opt := range append(defaultOpts, opts...) { + opt(r) + } + + h := r.handler + + return routing.New( + routing.WithRoutes([]routing.Route{ + { + "Index", + []string{ + http.MethodGet, + }, + "/", + h.Index, + }, + { + "Search", + []string{ + http.MethodPost, + }, + "/search", + h.Search, + }, + { + "Search By ID", + []string{ + http.MethodGet, + }, + "/search/{id}", + h.SearchByID, + }, + { + "Insert", + []string{ + http.MethodPost, + }, + "/insert", + h.Insert, + }, + { + "Multiple Insert", + []string{ + http.MethodPost, + }, + "/insert/multi", + h.MultiInsert, + }, + { + "Update", + []string{ + http.MethodPost, + http.MethodPatch, + http.MethodPut, + }, + "/update", + h.Update, + }, + { + "Multiple Update", + []string{ + http.MethodPost, + http.MethodPatch, + http.MethodPut, + }, + "/update/multi", + h.MultiUpdate, + }, + { + "Remove", + []string{ + http.MethodDelete, + }, + "/delete/{id}", + h.Remove, + }, + { + "Multiple Remove", + []string{ + http.MethodDelete, + http.MethodPost, + }, + "/delete/multi", + h.MultiRemove, + }, + { + "GetObject", + []string{ + http.MethodGet, + }, + "/object/{id}", + h.GetObject, + }, + }...)) +} diff --git a/pkg/gateway/backup/router/router_test.go b/pkg/gateway/backup/router/router_test.go new file mode 100644 index 00000000000..876b9574c48 --- /dev/null +++ b/pkg/gateway/backup/router/router_test.go @@ -0,0 +1,96 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "net/http" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errors" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want http.Handler + } + type test struct { + name string + args args + want want + checkFunc func(want, http.Handler) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got http.Handler) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/backup/service/backup.go b/pkg/gateway/backup/service/backup.go new file mode 100644 index 00000000000..bc50e649047 --- /dev/null +++ b/pkg/gateway/backup/service/backup.go @@ -0,0 +1,138 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + + "github.com/vdaas/vald/apis/grpc/manager/compressor" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" +) + +type Backup interface { + Start(ctx context.Context) (<-chan error, error) + GetObject(ctx context.Context, uuid string) (*payload.Backup_MetaVector, error) + GetLocation(ctx context.Context, uuid string) ([]string, error) + Register(ctx context.Context, vec *payload.Backup_MetaVector) error + RegisterMultiple(ctx context.Context, vecs *payload.Backup_MetaVectors) error + Remove(ctx context.Context, uuid string) error + RemoveMultiple(ctx context.Context, uuids ...string) error +} + +type backup struct { + addr string + client grpc.Client +} + +func NewBackup(opts ...BackupOption) (bu Backup, err error) { + b := new(backup) + for _, opt := range append(defaultBackupOpts, opts...) { + if err := opt(b); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + + return b, nil +} + +func (b *backup) Start(ctx context.Context) (<-chan error, error) { + return b.client.StartConnectionMonitor(ctx) +} + +func (b *backup) GetObject(ctx context.Context, uuid string) (vec *payload.Backup_MetaVector, err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + vec, err = compressor.NewBackupClient(conn).GetVector(ctx, &payload.Backup_GetVector_Request{ + Uuid: uuid, + }, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) GetLocation(ctx context.Context, uuid string) (ipList []string, err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + ips, err := compressor.NewBackupClient(conn).Locations(ctx, &payload.Backup_Locations_Request{ + Uuid: uuid, + }, copts...) + if err != nil { + return nil, err + } + ipList = ips.GetIp() + return + }) + return +} + +func (b *backup) Register(ctx context.Context, vec *payload.Backup_MetaVector) (err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).Register(ctx, vec, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) RegisterMultiple(ctx context.Context, vecs *payload.Backup_MetaVectors) (err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).RegisterMulti(ctx, vecs, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) Remove(ctx context.Context, uuid string) (err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).Remove(ctx, &payload.Backup_Remove_Request{ + Uuid: uuid, + }, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) RemoveMultiple(ctx context.Context, uuids ...string) (err error) { + req := new(payload.Backup_Remove_RequestMulti) + req.Uuids = uuids + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).RemoveMulti(ctx, req, copts...) + if err != nil { + return nil, err + } + return + }) + return +} diff --git a/pkg/gateway/backup/service/backup_test.go b/pkg/gateway/backup/service/backup_test.go new file mode 100644 index 00000000000..2d6c262f692 --- /dev/null +++ b/pkg/gateway/backup/service/backup_test.go @@ -0,0 +1,750 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewBackup(t *testing.T) { + type args struct { + opts []BackupOption + } + type want struct { + wantBu Backup + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Backup, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotBu Backup, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotBu, w.wantBu) { + return errors.Errorf("got = %v, want %v", gotBu, w.wantBu) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotBu, err := NewBackup(test.args.opts...) + if err := test.checkFunc(test.want, gotBu, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + got, err := b.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_GetObject(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + wantVec *payload.Backup_MetaVector + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Backup_MetaVector, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotVec *payload.Backup_MetaVector, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotVec, w.wantVec) { + return errors.Errorf("got = %v, want %v", gotVec, w.wantVec) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + gotVec, err := b.GetObject(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotVec, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_GetLocation(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + wantIpList []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotIpList []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotIpList, w.wantIpList) { + return errors.Errorf("got = %v, want %v", gotIpList, w.wantIpList) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + gotIpList, err := b.GetLocation(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotIpList, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_Register(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Backup_MetaVector + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.Register(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_RegisterMultiple(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Backup_MetaVectors + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.RegisterMultiple(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_Remove(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.Remove(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_RemoveMultiple(t *testing.T) { + type args struct { + ctx context.Context + uuids []string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.RemoveMultiple(test.args.ctx, test.args.uuids...) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/backup/service/doc.go b/pkg/gateway/backup/service/doc.go new file mode 100644 index 00000000000..c13956cbbe3 --- /dev/null +++ b/pkg/gateway/backup/service/doc.go @@ -0,0 +1,18 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service manages the main logic of server. +package service diff --git a/pkg/gateway/backup/service/option.go b/pkg/gateway/backup/service/option.go new file mode 100644 index 00000000000..3647333b074 --- /dev/null +++ b/pkg/gateway/backup/service/option.go @@ -0,0 +1,42 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import "github.com/vdaas/vald/internal/net/grpc" + +type BackupOption func(b *backup) error + +var ( + defaultBackupOpts = []BackupOption{} +) + +func WithBackupAddr(addr string) BackupOption { + return func(b *backup) error { + b.addr = addr + return nil + } +} + +func WithBackupClient(client grpc.Client) BackupOption { + return func(b *backup) error { + if client != nil { + b.client = client + } + return nil + } +} diff --git a/pkg/gateway/backup/service/option_test.go b/pkg/gateway/backup/service/option_test.go new file mode 100644 index 00000000000..ca7bca08cf7 --- /dev/null +++ b/pkg/gateway/backup/service/option_test.go @@ -0,0 +1,252 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestWithBackupAddr(t *testing.T) { + type T = interface{} + type args struct { + addr string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackupAddr(test.args.addr) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackupAddr(test.args.addr) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithBackupClient(t *testing.T) { + type T = interface{} + type args struct { + client grpc.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackupClient(test.args.client) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackupClient(test.args.client) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/backup/usecase/vald.go b/pkg/gateway/backup/usecase/vald.go new file mode 100644 index 00000000000..2e15ee8ac0f --- /dev/null +++ b/pkg/gateway/backup/usecase/vald.go @@ -0,0 +1,231 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package usecase + +import ( + "context" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + iconf "github.com/vdaas/vald/internal/config" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/metric" + "github.com/vdaas/vald/internal/observability" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/internal/servers/server" + "github.com/vdaas/vald/internal/servers/starter" + "github.com/vdaas/vald/pkg/gateway/backup/config" + handler "github.com/vdaas/vald/pkg/gateway/backup/handler/grpc" + "github.com/vdaas/vald/pkg/gateway/backup/handler/rest" + "github.com/vdaas/vald/pkg/gateway/backup/router" + "github.com/vdaas/vald/pkg/gateway/backup/service" +) + +type run struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + backup service.Backup +} + +func New(cfg *config.Data) (r runner.Runner, err error) { + eg := errgroup.Get() + + var ( + backup service.Backup + ) + + if addrs := cfg.Gateway.BackupManager.Client.Addrs; len(addrs) == 0 { + return nil, errors.ErrInvalidBackupConfig + } + + backupClientOptions := append( + cfg.Gateway.BackupManager.Client.Opts(), + grpc.WithErrGroup(eg), + ) + + var obs observability.Observability + if cfg.Observability.Enabled { + obs, err = observability.NewWithConfig(cfg.Observability) + if err != nil { + return nil, err + } + backupClientOptions = append( + backupClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + } + + backup, err = service.NewBackup( + service.WithBackupAddr(cfg.Gateway.BackupManager.Client.Addrs[0]), + service.WithBackupClient( + grpc.New(backupClientOptions...), + ), + ) + if err != nil { + return nil, err + } + + v := handler.New( + handler.WithBackup(backup), + handler.WithErrGroup(eg), + handler.WithReplicationCount(cfg.Gateway.IndexReplica), + handler.WithStreamConcurrency(cfg.Server.GetGRPCStreamConcurrency()), + ) + + grpcServerOptions := []server.Option{ + server.WithGRPCRegistFunc(func(srv *grpc.Server) { + vald.RegisterValdServer(srv, v) + }), + server.WithPreStopFunction(func() error { + // TODO notify another gateway and scheduler + return nil + }), + } + + if cfg.Observability.Enabled { + grpcServerOptions = append( + grpcServerOptions, + server.WithGRPCOption( + grpc.StatsHandler(metric.NewServerHandler()), + ), + ) + } + + srv, err := starter.New( + starter.WithConfig(cfg.Server), + starter.WithREST(func(sc *iconf.Server) []server.Option { + return []server.Option{ + server.WithHTTPHandler( + router.New( + router.WithHandler( + rest.New( + rest.WithVald(v), + ), + ), + ), + ), + } + }), + starter.WithGRPC(func(sc *iconf.Server) []server.Option { + return grpcServerOptions + }), + // TODO add GraphQL handler + ) + if err != nil { + return nil, err + } + + return &run{ + eg: eg, + cfg: cfg, + server: srv, + observability: obs, + filter: filter, + gateway: gateway, + metadata: metadata, + backup: backup, + }, nil +} + +func (r *run) PreStart(ctx context.Context) error { + if r.observability != nil { + return r.observability.PreStart(ctx) + } + return nil +} + +func (r *run) Start(ctx context.Context) (<-chan error, error) { + ech := make(chan error, 6) + var bech, fech, mech, gech, sech, oech <-chan error + var err error + if r.observability != nil { + oech = r.observability.Start(ctx) + } + if r.backup != nil { + bech, err = r.backup.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + if r.filter != nil { + fech, err = r.filter.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + if r.metadata != nil { + mech, err = r.metadata.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + if r.gateway != nil { + gech, err = r.gateway.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + sech = r.server.ListenAndServe(ctx) + r.eg.Go(safety.RecoverFunc(func() (err error) { + defer close(ech) + for { + select { + case <-ctx.Done(): + return ctx.Err() + case err = <-oech: + case err = <-bech: + case err = <-fech: + case err = <-gech: + case err = <-mech: + case err = <-sech: + } + if err != nil { + select { + case <-ctx.Done(): + return ctx.Err() + case ech <- err: + } + } + } + })) + return ech, nil +} + +func (r *run) PreStop(ctx context.Context) error { + return nil +} + +func (r *run) Stop(ctx context.Context) error { + if r.observability != nil { + r.observability.Stop(ctx) + } + return r.server.Shutdown(ctx) +} + +func (r *run) PostStop(ctx context.Context) error { + return nil +} diff --git a/pkg/gateway/backup/usecase/vald_test.go b/pkg/gateway/backup/usecase/vald_test.go new file mode 100644 index 00000000000..3002fca8f51 --- /dev/null +++ b/pkg/gateway/backup/usecase/vald_test.go @@ -0,0 +1,672 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package usecase + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/observability" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/servers/starter" + "github.com/vdaas/vald/pkg/gateway/backup/config" + "github.com/vdaas/vald/pkg/gateway/backup/service" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + cfg *config.Data + } + type want struct { + wantR runner.Runner + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, runner.Runner, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotR runner.Runner, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotR, w.wantR) { + return errors.Errorf("got = %v, want %v", gotR, w.wantR) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + cfg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + cfg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotR, err := New(test.args.cfg) + if err := test.checkFunc(test.want, gotR, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PreStart(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PreStart(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + got, err := r.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PreStop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PreStop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_Stop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.Stop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PostStop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PostStop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/README.md b/pkg/gateway/filter/README.md new file mode 100755 index 00000000000..9b8d2e1af5c --- /dev/null +++ b/pkg/gateway/filter/README.md @@ -0,0 +1 @@ +# server sample diff --git a/pkg/gateway/filter/config/config.go b/pkg/gateway/filter/config/config.go new file mode 100644 index 00000000000..6e4109fdabd --- /dev/null +++ b/pkg/gateway/filter/config/config.go @@ -0,0 +1,148 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package setting stores all server application settings +package config + +import ( + "github.com/vdaas/vald/internal/config" +) + +type GlobalConfig = config.GlobalConfig + +// Config represent a application setting data content (config.yaml). +// In K8s environment, this configuration is stored in K8s ConfigMap. +type Data struct { + config.GlobalConfig `json:",inline" yaml:",inline"` + + // Server represent all server configurations + Server *config.Servers `json:"server_config" yaml:"server_config"` + + // Observability represent observability configurations + Observability *config.Observability `json:"observability" yaml:"observability"` + + // Gateway represent agent gateway service configuration + Gateway *config.Gateway `json:"gateway" yaml:"gateway"` +} + +func NewConfig(path string) (cfg *Data, err error) { + err = config.Read(path, &cfg) + + if err != nil { + return nil, err + } + + if cfg != nil { + cfg.Bind() + } + + if cfg.Server != nil { + cfg.Server = cfg.Server.Bind() + } + + if cfg.Observability != nil { + cfg.Observability = cfg.Observability.Bind() + } + + if cfg.Gateway != nil { + cfg.Gateway = cfg.Gateway.Bind() + } + + return cfg, nil +} + +// func FakeData() { +// d := Data{ +// Version: "v0.0.1", +// Server: &config.Servers{ +// Servers: []*config.Server{ +// { +// Name: "agent-rest", +// Host: "127.0.0.1", +// Port: 8080, +// Mode: "REST", +// ProbeWaitTime: "3s", +// ShutdownDuration: "5s", +// HandlerTimeout: "5s", +// IdleTimeout: "2s", +// ReadHeaderTimeout: "1s", +// ReadTimeout: "1s", +// WriteTimeout: "1s", +// }, +// { +// Name: "agent-grpc", +// Host: "127.0.0.1", +// Port: 8082, +// Mode: "GRPC", +// }, +// }, +// MetricsServers: []*config.Server{ +// { +// Name: "pprof", +// Host: "127.0.0.1", +// Port: 6060, +// Mode: "REST", +// ProbeWaitTime: "3s", +// ShutdownDuration: "5s", +// HandlerTimeout: "5s", +// IdleTimeout: "2s", +// ReadHeaderTimeout: "1s", +// ReadTimeout: "1s", +// WriteTimeout: "1s", +// }, +// }, +// HealthCheckServers: []*config.Server{ +// { +// Name: "livenesss", +// Host: "127.0.0.1", +// Port: 3000, +// }, +// { +// Name: "readiness", +// Host: "127.0.0.1", +// Port: 3001, +// }, +// }, +// StartUpStrategy: []string{ +// "livenesss", +// "pprof", +// "agent-grpc", +// "agent-rest", +// "readiness", +// }, +// ShutdownStrategy: []string{ +// "readiness", +// "agent-rest", +// "agent-grpc", +// "pprof", +// "livenesss", +// }, +// FullShutdownDuration: "30s", +// TLS: &config.TLS{ +// Enabled: false, +// Cert: "/path/to/cert", +// Key: "/path/to/key", +// CA: "/path/to/ca", +// }, +// }, +// Gateway: &config.Gateway{ +// AgentPort: 8080, +// AgentName: "vald-agent", +// BackoffEnabled: false,, +// }, +// } +// fmt.Println(config.ToRawYaml(d)) +// } diff --git a/pkg/gateway/filter/config/config_test.go b/pkg/gateway/filter/config/config_test.go new file mode 100644 index 00000000000..e8090717ead --- /dev/null +++ b/pkg/gateway/filter/config/config_test.go @@ -0,0 +1,101 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package setting stores all server application settings +package config + +import ( + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errors" + "go.uber.org/goleak" +) + +func TestNewConfig(t *testing.T) { + type args struct { + path string + } + type want struct { + wantCfg *Data + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, *Data, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCfg *Data, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCfg, w.wantCfg) { + return errors.Errorf("got = %v, want %v", gotCfg, w.wantCfg) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + path: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + path: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotCfg, err := NewConfig(test.args.path) + if err := test.checkFunc(test.want, gotCfg, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/handler/doc.go b/pkg/gateway/filter/handler/doc.go new file mode 100644 index 00000000000..86b6d1869df --- /dev/null +++ b/pkg/gateway/filter/handler/doc.go @@ -0,0 +1,17 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package handler diff --git a/pkg/gateway/filter/handler/grpc/checklist.go b/pkg/gateway/filter/handler/grpc/checklist.go new file mode 100644 index 00000000000..1d3cdc4b476 --- /dev/null +++ b/pkg/gateway/filter/handler/grpc/checklist.go @@ -0,0 +1,141 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package grpc + +import ( + "sync" + "sync/atomic" + "unsafe" +) + +type checkList struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int +} + +type readOnlyCheckList struct { + m map[string]*entryCheckList + amended bool +} + +var expungedCheckList = unsafe.Pointer(new(struct{})) + +type entryCheckList struct { + p unsafe.Pointer +} + +func (m *checkList) Exists(key string) bool { + read, _ := m.read.Load().(readOnlyCheckList) + e, ok := read.m[key] + if !ok && read.amended { + m.mu.Lock() + read, _ = m.read.Load().(readOnlyCheckList) + e, ok = read.m[key] + if !ok && read.amended { + e, ok = m.dirty[key] + m.missLocked() + } + m.mu.Unlock() + } + if !ok { + return false + } + p := atomic.LoadPointer(&e.p) + if p == nil || p == expungedCheckList { + return false + } + return true +} + +func (m *checkList) Check(key string) { + value := struct{}{} + read, _ := m.read.Load().(readOnlyCheckList) + if e, ok := read.m[key]; ok && e.tryStore(&value) { + return + } + + m.mu.Lock() + read, _ = m.read.Load().(readOnlyCheckList) + if e, ok := read.m[key]; ok { + if e.unexpungeLocked() { + m.dirty[key] = e + } + atomic.StorePointer(&e.p, unsafe.Pointer(&value)) + } else if e, ok := m.dirty[key]; ok { + atomic.StorePointer(&e.p, unsafe.Pointer(&value)) + } else { + if !read.amended { + m.dirtyLocked() + m.read.Store(readOnlyCheckList{m: read.m, amended: true}) + } + m.dirty[key] = &entryCheckList{p: unsafe.Pointer(&value)} + } + m.mu.Unlock() +} + +func (e *entryCheckList) tryStore(i *struct{}) bool { + for { + p := atomic.LoadPointer(&e.p) + if p == expungedCheckList { + return false + } + if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) { + return true + } + } +} + +func (e *entryCheckList) unexpungeLocked() (wasExpunged bool) { + return atomic.CompareAndSwapPointer(&e.p, expungedCheckList, nil) +} + +func (m *checkList) missLocked() { + m.misses++ + if m.misses < len(m.dirty) { + return + } + m.read.Store(readOnlyCheckList{m: m.dirty}) + m.dirty = nil + m.misses = 0 +} + +func (m *checkList) dirtyLocked() { + if m.dirty != nil { + return + } + + read, _ := m.read.Load().(readOnlyCheckList) + m.dirty = make(map[string]*entryCheckList, len(read.m)) + for k, e := range read.m { + if !e.tryExpungeLocked() { + m.dirty[k] = e + } + } +} + +func (e *entryCheckList) tryExpungeLocked() (isExpunged bool) { + p := atomic.LoadPointer(&e.p) + for p == nil { + if atomic.CompareAndSwapPointer(&e.p, nil, expungedCheckList) { + return true + } + p = atomic.LoadPointer(&e.p) + } + return p == expungedCheckList +} diff --git a/pkg/gateway/filter/handler/grpc/checklist_test.go b/pkg/gateway/filter/handler/grpc/checklist_test.go new file mode 100644 index 00000000000..805308ea276 --- /dev/null +++ b/pkg/gateway/filter/handler/grpc/checklist_test.go @@ -0,0 +1,601 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package grpc + +import ( + "reflect" + "sync" + "sync/atomic" + "testing" + "unsafe" + + "github.com/vdaas/vald/internal/errors" +) + +func Test_checkList_Exists(t *testing.T) { + type args struct { + key string + } + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + want bool + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got bool) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + got := m.Exists(test.args.key) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_checkList_Check(t *testing.T) { + type args struct { + key string + } + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + m.Check(test.args.key) + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + +func Test_entryCheckList_tryStore(t *testing.T) { + type args struct { + i *struct{} + } + type fields struct { + p unsafe.Pointer + } + type want struct { + want bool + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got bool) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + i: struct{}{}, + }, + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + i: struct{}{}, + }, + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + e := &entryCheckList{ + p: test.fields.p, + } + + got := e.tryStore(test.args.i) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_entryCheckList_unexpungeLocked(t *testing.T) { + type fields struct { + p unsafe.Pointer + } + type want struct { + wantWasExpunged bool + } + type test struct { + name string + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want, gotWasExpunged bool) error { + if !reflect.DeepEqual(gotWasExpunged, w.wantWasExpunged) { + return errors.Errorf("got = %v, want %v", gotWasExpunged, w.wantWasExpunged) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + e := &entryCheckList{ + p: test.fields.p, + } + + gotWasExpunged := e.unexpungeLocked() + if err := test.checkFunc(test.want, gotWasExpunged); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_checkList_missLocked(t *testing.T) { + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + } + type test struct { + name string + fields fields + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + m.missLocked() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + +func Test_checkList_dirtyLocked(t *testing.T) { + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + } + type test struct { + name string + fields fields + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + m.dirtyLocked() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + +func Test_entryCheckList_tryExpungeLocked(t *testing.T) { + type fields struct { + p unsafe.Pointer + } + type want struct { + wantIsExpunged bool + } + type test struct { + name string + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want, gotIsExpunged bool) error { + if !reflect.DeepEqual(gotIsExpunged, w.wantIsExpunged) { + return errors.Errorf("got = %v, want %v", gotIsExpunged, w.wantIsExpunged) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + e := &entryCheckList{ + p: test.fields.p, + } + + gotIsExpunged := e.tryExpungeLocked() + if err := test.checkFunc(test.want, gotIsExpunged); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/handler/grpc/handler.go b/pkg/gateway/filter/handler/grpc/handler.go new file mode 100644 index 00000000000..c944e74331c --- /dev/null +++ b/pkg/gateway/filter/handler/grpc/handler.go @@ -0,0 +1,851 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "context" + "fmt" + "math" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/kpango/fuid" + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/info" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/status" + "github.com/vdaas/vald/internal/observability/trace" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/pkg/gateway/filter/service" +) + +type server struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int +} + +func New(opts ...Option) vald.ValdServer { + s := new(server) + + for _, opt := range append(defaultOpts, opts...) { + opt(s) + } + return s +} + +func (s *server) Exists(ctx context.Context, meta *payload.Object_ID) (*payload.Object_ID, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Exists") + defer func() { + if span != nil { + span.End() + } + }() + uuid, err := s.metadata.GetUUID(ctx, meta.GetId()) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Exists API meta %s's uuid not found", meta.GetId()), err, meta.GetId(), info.Get()) + } + return &payload.Object_ID{ + Id: uuid, + }, nil +} + +func (s *server) Search(ctx context.Context, req *payload.Search_Request) (res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Search") + defer func() { + if span != nil { + span.End() + } + }() + return s.search(ctx, req.GetConfig(), + func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) { + return ac.Search(ctx, req, copts...) + }) +} + +func (s *server) SearchByID(ctx context.Context, req *payload.Search_IDRequest) ( + res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.SearchByID") + defer func() { + if span != nil { + span.End() + } + }() + metaID := req.GetId() + req.Id, err = s.metadata.GetUUID(ctx, metaID) + if err != nil { + req.Id = metaID + log.Errorf("error at SearchByID\t%v", err) + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("SearchByID API meta %s's uuid not found", metaID), err, req, info.Get()) + } + return s.search(ctx, req.GetConfig(), + func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) { + return ac.SearchByID(ctx, req, copts...) + }) +} + +func (s *server) search(ctx context.Context, cfg *payload.Search_Config, + f func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error)) ( + res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.search") + defer func() { + if span != nil { + span.End() + } + }() + maxDist := uint32(math.MaxUint32) + num := int(cfg.GetNum()) + res = new(payload.Search_Response) + res.Results = make([]*payload.Object_Distance, 0, s.gateway.GetAgentCount(ctx)*num) + dch := make(chan *payload.Object_Distance, cap(res.GetResults())/2) + eg, ectx := errgroup.New(ctx) + var cancel context.CancelFunc + var timeout time.Duration + if to := cfg.GetTimeout(); to != 0 { + timeout = time.Duration(to) + } else { + timeout = s.timeout + } + ectx, cancel = context.WithTimeout(ectx, timeout) + + eg.Go(safety.RecoverFunc(func() error { + defer cancel() + // cl := new(checkList) + visited := make(map[string]bool, len(res.Results)) + mu := sync.RWMutex{} + return s.gateway.BroadCast(ectx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + r, err := f(ctx, ac, copts...) + if err != nil { + log.Debug(err) + return nil + } + for _, dist := range r.GetResults() { + if dist.GetDistance() > math.Float32frombits(atomic.LoadUint32(&maxDist)) { + return nil + } + id := dist.GetId() + mu.RLock() + if !visited[id] { + mu.RUnlock() + mu.Lock() + visited[id] = true + mu.Unlock() + dch <- dist + } else { + mu.RUnlock() + } + // if !cl.Exists(id) { + // dch <- dist + // cl.Check(id) + // } + } + return nil + }) + })) + for { + select { + case <-ectx.Done(): + err = eg.Wait() + if err != nil { + log.Error(err) + } + close(dch) + if len(res.GetResults()) > num && num != 0 { + res.Results = res.Results[:num] + } + uuids := make([]string, 0, len(res.Results)) + for _, r := range res.Results { + uuids = append(uuids, r.GetId()) + } + if s.metadata != nil { + metas, merr := s.metadata.GetMetas(ctx, uuids...) + if merr != nil { + log.Error(merr) + err = errors.Wrap(err, merr.Error()) + } + for i, k := range metas { + if len(k) != 0 { + res.Results[i].Id = k + } + } + } + if s.filter != nil { + r, ferr := s.filter.FilterSearch(ctx, res) + if ferr == nil { + res = r + } else { + err = errors.Wrap(err, ferr.Error()) + } + } + if err != nil { + return res, status.WrapWithInternal(fmt.Sprintf("failed to search request %#v", cfg), err, info.Get()) + } + return res, nil + case dist := <-dch: + if len(res.GetResults()) >= num && + dist.GetDistance() < math.Float32frombits(atomic.LoadUint32(&maxDist)) { + atomic.StoreUint32(&maxDist, math.Float32bits(dist.GetDistance())) + } + switch len(res.GetResults()) { + case 0: + res.Results = append(res.Results, dist) + continue + case 1: + if res.GetResults()[0].GetDistance() <= dist.GetDistance() { + res.Results = append(res.Results, dist) + } else { + res.Results = append([]*payload.Object_Distance{dist}, res.Results[0]) + } + continue + } + + pos := len(res.GetResults()) + for idx := pos; idx >= 1; idx-- { + if res.GetResults()[idx-1].GetDistance() <= dist.GetDistance() { + pos = idx - 1 + break + } + } + switch { + case pos == len(res.GetResults()): + res.Results = append([]*payload.Object_Distance{dist}, res.Results...) + case pos == len(res.GetResults())-1: + res.Results = append(res.GetResults(), dist) + case pos >= 0: + res.Results = append(res.GetResults()[:pos+1], res.GetResults()[pos:]...) + res.Results[pos+1] = dist + } + if len(res.GetResults()) > num && num != 0 { + res.Results = res.GetResults()[:num] + } + } + } +} + +func (s *server) StreamSearch(stream vald.Vald_StreamSearchServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamSearch") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Search_Request) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Search(ctx, data.(*payload.Search_Request)) + }) +} + +func (s *server) StreamSearchByID(stream vald.Vald_StreamSearchByIDServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamSearchByID") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Search_IDRequest) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.SearchByID(ctx, data.(*payload.Search_IDRequest)) + }) +} + +func (s *server) Insert(ctx context.Context, vec *payload.Object_Vector) (ce *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Insert") + defer func() { + if span != nil { + span.End() + } + }() + meta := vec.GetId() + exists, err := s.metadata.Exists(ctx, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal( + fmt.Sprintf("Insert API meta %s couldn't check meta already exists or not", meta), err, info.Get()) + } + if exists { + err = errors.Wrap(err, errors.ErrMetaDataAlreadyExists(meta).Error()) + if span != nil { + span.SetStatus(trace.StatusCodeAlreadyExists(err.Error())) + } + return nil, status.WrapWithAlreadyExists(fmt.Sprintf("Insert API meta %s already exists", meta), err, info.Get()) + } + + uuid := fuid.String() + err = s.metadata.SetUUIDandMeta(ctx, uuid, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Insert API meta %s & uuid %s couldn't store", meta, uuid), err, info.Get()) + } + vec.Id = uuid + mu := new(sync.Mutex) + targets := make([]string, 0, s.replica) + err = s.gateway.DoMulti(ctx, s.replica, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) (err error) { + _, err = ac.Insert(ctx, vec, copts...) + if err != nil { + if err == errors.ErrRPCCallFailed(target, context.Canceled) { + return nil + } + return err + } + target = strings.SplitN(target, ":", 2)[0] + mu.Lock() + targets = append(targets, target) + mu.Unlock() + return nil + }) + if err != nil { + err = errors.Wrapf(err, "Insert API (do multiple) failed to Insert uuid = %s\tmeta = %s\t info = %#v", uuid, meta, info.Get()) + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Insert API failed to Execute DoMulti error = %s", err.Error()), err, info.Get()) + } + if s.backup != nil { + vecs := &payload.Backup_MetaVector{ + Uuid: uuid, + Meta: meta, + Ips: targets, + } + if vec != nil { + vecs.Vector = vec.GetVector() + } + err = s.backup.Register(ctx, vecs) + if err != nil { + err = errors.Wrapf(err, "Insert API (backup.Register) failed to Backup Vectors = %#v\t info = %#v", vecs, info.Get()) + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(err.Error(), err) + } + } + log.Debugf("Insert API insert succeeded to %v", targets) + return new(payload.Empty), nil +} + +func (s *server) StreamInsert(stream vald.Vald_StreamInsertServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamInsert") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Insert(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiInsert(ctx context.Context, vecs *payload.Object_Vectors) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiInsert") + defer func() { + if span != nil { + span.End() + } + }() + metaMap := make(map[string]string) + metas := make([]string, 0, len(vecs.GetVectors())) + for i, vec := range vecs.GetVectors() { + uuid := fuid.String() + meta := vec.GetId() + metaMap[uuid] = meta + metas = append(metas, meta) + vecs.Vectors[i].Id = uuid + } + + for _, meta := range metas { + exists, err := s.metadata.Exists(ctx, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal( + fmt.Sprintf("MultiInsert API couldn't check metadata exists or not metas = %v", metas), err, info.Get()) + } + if exists { + if span != nil { + span.SetStatus(trace.StatusCodeAlreadyExists(err.Error())) + } + return nil, status.WrapWithAlreadyExists( + fmt.Sprintf("MultiInsert API failed metadata already exists meta = %s", meta), err, info.Get()) + } + } + + err = s.metadata.SetUUIDandMetas(ctx, metaMap) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed SetUUIDandMetas %#v", metaMap), err, info.Get()) + } + + mu := new(sync.Mutex) + targets := make([]string, 0, s.replica) + gerr := s.gateway.DoMulti(ctx, s.replica, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) (err error) { + _, err = ac.MultiInsert(ctx, vecs, copts...) + if err != nil { + return err + } + target = strings.SplitN(target, ":", 2)[0] + mu.Lock() + targets = append(targets, target) + mu.Unlock() + return nil + }) + if gerr != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed request %#v", vecs), errors.Wrap(gerr, err.Error()), info.Get()) + } + + if s.backup != nil { + mvecs := new(payload.Backup_MetaVectors) + mvecs.Vectors = make([]*payload.Backup_MetaVector, 0, len(vecs.GetVectors())) + for _, vec := range vecs.GetVectors() { + uuid := vec.GetId() + mvecs.Vectors = append(mvecs.Vectors, &payload.Backup_MetaVector{ + Uuid: uuid, + Meta: metaMap[uuid], + Vector: vec.GetVector(), + Ips: targets, + }) + } + err = s.backup.RegisterMultiple(ctx, mvecs) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed RegisterMultiple %#v", mvecs), err, info.Get()) + } + } + return new(payload.Empty), nil +} + +func (s *server) Update(ctx context.Context, vec *payload.Object_Vector) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Update") + defer func() { + if span != nil { + span.End() + } + }() + meta := vec.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Update API failed GetUUID meta = %s", meta), err, info.Get()) + } + vec.Id = uuid + locs, err := s.backup.GetLocation(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Update API failed GetLocation meta = %s, uuid = %s", meta, uuid), err, info.Get()) + } + lmap := make(map[string]struct{}, len(locs)) + for _, loc := range locs { + lmap[loc] = struct{}{} + } + err = s.gateway.BroadCast(ctx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + target = strings.SplitN(target, ":", 2)[0] + _, ok := lmap[target] + if ok { + _, err = ac.Update(ctx, vec, copts...) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Update API failed request %#v", vec), err, info.Get()) + } + mvec := &payload.Backup_MetaVector{ + Uuid: uuid, + Meta: meta, + Vector: vec.GetVector(), + Ips: locs, + } + err = s.backup.Register(ctx, mvec) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Update API failed backup %#v", vec), err, info.Get()) + } + + return new(payload.Empty), nil +} + +func (s *server) StreamUpdate(stream vald.Vald_StreamUpdateServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamUpdate") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Update(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiUpdate(ctx context.Context, vecs *payload.Object_Vectors) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiUpdate") + defer func() { + if span != nil { + span.End() + } + }() + ids := make([]string, 0, len(vecs.GetVectors())) + for _, vec := range vecs.GetVectors() { + ids = append(ids, vec.GetId()) + } + _, err = s.MultiRemove(ctx, &payload.Object_IDs{ + Ids: ids, + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiUpdate API failed Remove request %#v", ids), err, info.Get()) + } + _, err = s.MultiInsert(ctx, vecs) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiUpdate API failed Insert request %#v", vecs), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) Upsert(ctx context.Context, vec *payload.Object_Vector) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Upsert") + defer func() { + if span != nil { + span.End() + } + }() + + meta := vec.GetId() + exists, errs := s.metadata.Exists(ctx, meta) + if errs != nil { + log.Error(errs) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(errs.Error())) + } + } + + if exists { + _, err := s.Update(ctx, vec) + if err != nil { + errs = errors.Wrap(errs, err.Error()) + } + } else { + _, err := s.Insert(ctx, vec) + if err != nil { + errs = errors.Wrap(errs, err.Error()) + } + } + + return new(payload.Empty), errs +} + +func (s *server) StreamUpsert(stream vald.Vald_StreamUpsertServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamUpsert") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Upsert(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiUpsert(ctx context.Context, vecs *payload.Object_Vectors) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiUpsert") + defer func() { + if span != nil { + span.End() + } + }() + + insertVecs := make([]*payload.Object_Vector, 0, len(vecs.GetVectors())) + updateVecs := make([]*payload.Object_Vector, 0, len(vecs.GetVectors())) + + var errs error + for _, vec := range vecs.GetVectors() { + exists, err := s.metadata.Exists(ctx, vec.GetId()) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + errs = errors.Wrap(errs, err.Error()) + } + + if exists { + updateVecs = append(updateVecs, vec) + } else { + insertVecs = append(insertVecs, vec) + } + } + + eg, ectx := errgroup.New(ctx) + + eg.Go(safety.RecoverFunc(func() error { + var err error + if len(updateVecs) > 0 { + _, err = s.MultiUpdate(ectx, &payload.Object_Vectors{ + Vectors: updateVecs, + }) + } + return err + })) + + eg.Go(safety.RecoverFunc(func() error { + var err error + if len(insertVecs) > 0 { + _, err = s.MultiInsert(ectx, &payload.Object_Vectors{ + Vectors: insertVecs, + }) + } + return err + })) + + err := eg.Wait() + if err != nil { + errs = errors.Wrap(errs, err.Error()) + return nil, status.WrapWithInternal("MultiUpsert API failed", errs, info.Get()) + } + + return new(payload.Empty), errs +} + +func (s *server) Remove(ctx context.Context, id *payload.Object_ID) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Remove") + defer func() { + if span != nil { + span.End() + } + }() + meta := id.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Remove API meta %s's uuid not found", meta), err, info.Get()) + } + locs, err := s.backup.GetLocation(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Remove API failed GetLocation meta = %s, uuid = %s", meta, uuid), err, info.Get()) + } + lmap := make(map[string]struct{}, len(locs)) + for _, loc := range locs { + lmap[loc] = struct{}{} + } + err = s.gateway.BroadCast(ctx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + _, ok := lmap[target] + if ok { + _, err = ac.Remove(ctx, &payload.Object_ID{ + Id: uuid, + }, copts...) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed request uuid %s", uuid), err, info.Get()) + } + _, err = s.metadata.DeleteMeta(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed Delete metadata uuid = %s", uuid), err, info.Get()) + } + err = s.backup.Remove(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed to Remove backup uuid = %s", uuid), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) StreamRemove(stream vald.Vald_StreamRemoveServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamRemove") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_ID) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Remove(ctx, data.(*payload.Object_ID)) + }) +} + +func (s *server) MultiRemove(ctx context.Context, ids *payload.Object_IDs) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiRemove") + defer func() { + if span != nil { + span.End() + } + }() + uuids, err := s.metadata.GetUUIDs(ctx, ids.GetIds()...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("MultiRemove API meta datas %v's uuid not found", ids.GetIds()), err, info.Get()) + } + lmap := make(map[string][]string, s.gateway.GetAgentCount(ctx)) + for _, uuid := range uuids { + locs, err := s.backup.GetLocation(ctx, uuid) + if err != nil { + return nil, status.WrapWithNotFound(fmt.Sprintf("MultiRemove API failed to get uuid %s's location ", uuid), err, info.Get()) + } + for _, loc := range locs { + lmap[loc] = append(lmap[loc], uuid) + } + } + err = s.gateway.BroadCast(ctx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + uuids, ok := lmap[target] + if ok { + _, err := ac.MultiRemove(ctx, &payload.Object_IDs{ + Ids: uuids, + }, copts...) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to request uuids %v metas %v ", uuids, ids.GetIds()), err, info.Get()) + } + _, err = s.metadata.DeleteMetas(ctx, uuids...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to DeleteMetas uuids %v ", uuids), err, info.Get()) + } + err = s.backup.RemoveMultiple(ctx, uuids...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to Remove backup uuids %v ", uuids), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) GetObject(ctx context.Context, id *payload.Object_ID) (vec *payload.Backup_MetaVector, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.GetObject") + defer func() { + if span != nil { + span.End() + } + }() + meta := id.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("GetObject API meta %s's uuid not found", meta), err, info.Get()) + } + vec, err = s.backup.GetObject(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("GetObject API meta %s uuid %s Object not found", meta, uuid), err, info.Get()) + } + return vec, nil +} + +func (s *server) StreamGetObject(stream vald.Vald_StreamGetObjectServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamGetObject") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_ID) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.GetObject(ctx, data.(*payload.Object_ID)) + }) +} diff --git a/pkg/gateway/filter/handler/grpc/handler_test.go b/pkg/gateway/filter/handler/grpc/handler_test.go new file mode 100644 index 00000000000..d68d54af2cf --- /dev/null +++ b/pkg/gateway/filter/handler/grpc/handler_test.go @@ -0,0 +1,2440 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "context" + "reflect" + "testing" + "time" + + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/pkg/gateway/filter/service" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want vald.ValdServer + } + type test struct { + name string + args args + want want + checkFunc func(want, vald.ValdServer) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got vald.ValdServer) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Exists(t *testing.T) { + type args struct { + ctx context.Context + meta *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Object_ID + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Object_ID, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Object_ID, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Exists(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Search(t *testing.T) { + type args struct { + ctx context.Context + req *payload.Search_Request + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.Search(test.args.ctx, test.args.req) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_SearchByID(t *testing.T) { + type args struct { + ctx context.Context + req *payload.Search_IDRequest + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.SearchByID(test.args.ctx, test.args.req) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_search(t *testing.T) { + type args struct { + ctx context.Context + cfg *payload.Search_Config + f func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + cfg: nil, + f: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + cfg: nil, + f: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.search(test.args.ctx, test.args.cfg, test.args.f) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamSearch(t *testing.T) { + type args struct { + stream vald.Vald_StreamSearchServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamSearch(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamSearchByID(t *testing.T) { + type args struct { + stream vald.Vald_StreamSearchByIDServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamSearchByID(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Insert(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantCe *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCe *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCe, w.wantCe) { + return errors.Errorf("got = %v, want %v", gotCe, w.wantCe) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotCe, err := s.Insert(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, gotCe, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamInsert(t *testing.T) { + type args struct { + stream vald.Vald_StreamInsertServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamInsert(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiInsert(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiInsert(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Update(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.Update(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamUpdate(t *testing.T) { + type args struct { + stream vald.Vald_StreamUpdateServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamUpdate(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiUpdate(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiUpdate(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Upsert(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Upsert(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamUpsert(t *testing.T) { + type args struct { + stream vald.Vald_StreamUpsertServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamUpsert(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiUpsert(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.MultiUpsert(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Remove(t *testing.T) { + type args struct { + ctx context.Context + id *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Remove(test.args.ctx, test.args.id) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamRemove(t *testing.T) { + type args struct { + stream vald.Vald_StreamRemoveServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamRemove(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiRemove(t *testing.T) { + type args struct { + ctx context.Context + ids *payload.Object_IDs + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + ids: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + ids: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiRemove(test.args.ctx, test.args.ids) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_GetObject(t *testing.T) { + type args struct { + ctx context.Context + id *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantVec *payload.Backup_MetaVector + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Backup_MetaVector, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotVec *payload.Backup_MetaVector, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotVec, w.wantVec) { + return errors.Errorf("got = %v, want %v", gotVec, w.wantVec) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotVec, err := s.GetObject(test.args.ctx, test.args.id) + if err := test.checkFunc(test.want, gotVec, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamGetObject(t *testing.T) { + type args struct { + stream vald.Vald_StreamGetObjectServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamGetObject(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/handler/grpc/option.go b/pkg/gateway/filter/handler/grpc/option.go new file mode 100644 index 00000000000..2b93084eb9e --- /dev/null +++ b/pkg/gateway/filter/handler/grpc/option.go @@ -0,0 +1,103 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "time" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/timeutil" + "github.com/vdaas/vald/pkg/gateway/filter/service" +) + +type Option func(*server) + +var ( + defaultOpts = []Option{ + WithErrGroup(errgroup.Get()), + WithReplicationCount(3), + WithStreamConcurrency(20), + WithTimeout("5s"), + } +) + +func WithGateway(g service.Gateway) Option { + return func(s *server) { + if g != nil { + s.gateway = g + } + } +} + +func WithMeta(m service.Meta) Option { + return func(s *server) { + if m != nil { + s.metadata = m + } + } +} + +func WithBackup(b service.Backup) Option { + return func(s *server) { + if b != nil { + s.backup = b + } + } +} + +func WithFilters(filter service.Filter) Option { + return func(s *server) { + if filter != nil { + s.filter = filter + } + } +} + +func WithErrGroup(eg errgroup.Group) Option { + return func(s *server) { + if eg != nil { + s.eg = eg + } + } +} + +func WithTimeout(dur string) Option { + return func(s *server) { + d, err := timeutil.Parse(dur) + if err != nil { + d = time.Second * 10 + } + s.timeout = d + } +} + +func WithReplicationCount(rep int) Option { + return func(s *server) { + if rep > 1 { + s.replica = rep + } + } +} + +func WithStreamConcurrency(c int) Option { + return func(s *server) { + if c != 0 { + s.streamConcurrency = c + } + } +} diff --git a/pkg/gateway/filter/handler/grpc/option_test.go b/pkg/gateway/filter/handler/grpc/option_test.go new file mode 100644 index 00000000000..d211805b790 --- /dev/null +++ b/pkg/gateway/filter/handler/grpc/option_test.go @@ -0,0 +1,931 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "testing" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/pkg/gateway/filter/service" + + "go.uber.org/goleak" +) + +func TestWithGateway(t *testing.T) { + type T = interface{} + type args struct { + g service.Gateway + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + g: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + g: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithGateway(test.args.g) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithGateway(test.args.g) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMeta(t *testing.T) { + type T = interface{} + type args struct { + m service.Meta + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + m: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + m: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMeta(test.args.m) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMeta(test.args.m) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithBackup(t *testing.T) { + type T = interface{} + type args struct { + b service.Backup + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + b: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + b: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackup(test.args.b) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackup(test.args.b) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithFilters(t *testing.T) { + type T = interface{} + type args struct { + filter service.Filter + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + filter: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + filter: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithFilters(test.args.filter) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithFilters(test.args.filter) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithErrGroup(t *testing.T) { + type T = interface{} + type args struct { + eg errgroup.Group + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithErrGroup(test.args.eg) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithErrGroup(test.args.eg) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithTimeout(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithTimeout(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithTimeout(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithReplicationCount(t *testing.T) { + type T = interface{} + type args struct { + rep int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + rep: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + rep: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithReplicationCount(test.args.rep) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithReplicationCount(test.args.rep) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithStreamConcurrency(t *testing.T) { + type T = interface{} + type args struct { + c int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + c: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + c: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithStreamConcurrency(test.args.c) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithStreamConcurrency(test.args.c) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/filter/handler/rest/handler.go b/pkg/gateway/filter/handler/rest/handler.go new file mode 100644 index 00000000000..c9b9b962660 --- /dev/null +++ b/pkg/gateway/filter/handler/rest/handler.go @@ -0,0 +1,131 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "net/http" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/net/http/dump" + "github.com/vdaas/vald/internal/net/http/json" +) + +type Handler interface { + Index(w http.ResponseWriter, r *http.Request) (int, error) + Exists(w http.ResponseWriter, r *http.Request) (int, error) + Search(w http.ResponseWriter, r *http.Request) (int, error) + SearchByID(w http.ResponseWriter, r *http.Request) (int, error) + Insert(w http.ResponseWriter, r *http.Request) (int, error) + MultiInsert(w http.ResponseWriter, r *http.Request) (int, error) + Update(w http.ResponseWriter, r *http.Request) (int, error) + MultiUpdate(w http.ResponseWriter, r *http.Request) (int, error) + Remove(w http.ResponseWriter, r *http.Request) (int, error) + MultiRemove(w http.ResponseWriter, r *http.Request) (int, error) + GetObject(w http.ResponseWriter, r *http.Request) (int, error) +} + +type handler struct { + vald vald.ValdServer +} + +func New(opts ...Option) Handler { + h := new(handler) + + for _, opt := range append(defaultOpts, opts...) { + opt(h) + } + return h +} + +func (h *handler) Index(w http.ResponseWriter, r *http.Request) (int, error) { + data := make(map[string]interface{}) + return json.Handler(w, r, &data, func() (interface{}, error) { + return dump.Request(nil, data, r) + }) +} + +func (h *handler) Search(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Search_Request + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Search(r.Context(), req) + }) +} + +func (h *handler) SearchByID(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Search_IDRequest + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.SearchByID(r.Context(), req) + }) +} + +func (h *handler) Insert(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vector + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Insert(r.Context(), req) + }) +} + +func (h *handler) MultiInsert(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vectors + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiInsert(r.Context(), req) + }) +} + +func (h *handler) Update(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vector + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Update(r.Context(), req) + }) +} + +func (h *handler) MultiUpdate(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vectors + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiUpdate(r.Context(), req) + }) +} + +func (h *handler) Remove(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Remove(r.Context(), req) + }) +} + +func (h *handler) MultiRemove(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_IDs + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiRemove(r.Context(), req) + }) +} + +func (h *handler) GetObject(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.GetObject(r.Context(), req) + }) +} + +func (h *handler) Exists(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Exists(r.Context(), req) + }) +} diff --git a/pkg/gateway/filter/handler/rest/handler_test.go b/pkg/gateway/filter/handler/rest/handler_test.go new file mode 100644 index 00000000000..37fee9c24f7 --- /dev/null +++ b/pkg/gateway/filter/handler/rest/handler_test.go @@ -0,0 +1,1101 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "net/http" + "reflect" + "testing" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/internal/errors" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want Handler + } + type test struct { + name string + args args + want want + checkFunc func(want, Handler) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got Handler) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Index(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + want int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + got, err := h.Index(test.args.w, test.args.r) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Search(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Search(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_SearchByID(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.SearchByID(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Insert(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Insert(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiInsert(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiInsert(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Update(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Update(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiUpdate(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiUpdate(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Remove(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Remove(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiRemove(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiRemove(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_GetObject(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.GetObject(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Exists(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Exists(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/handler/rest/option.go b/pkg/gateway/filter/handler/rest/option.go new file mode 100644 index 00000000000..c684ad7ec83 --- /dev/null +++ b/pkg/gateway/filter/handler/rest/option.go @@ -0,0 +1,32 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import "github.com/vdaas/vald/apis/grpc/gateway/vald" + +type Option func(*handler) + +var ( + defaultOpts = []Option{} +) + +func WithVald(v vald.ValdServer) Option { + return func(h *handler) { + h.vald = v + } +} diff --git a/pkg/gateway/filter/handler/rest/option_test.go b/pkg/gateway/filter/handler/rest/option_test.go new file mode 100644 index 00000000000..3f900a77c5c --- /dev/null +++ b/pkg/gateway/filter/handler/rest/option_test.go @@ -0,0 +1,139 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "testing" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + + "go.uber.org/goleak" +) + +func TestWithVald(t *testing.T) { + type T = interface{} + type args struct { + v vald.ValdServer + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + v: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + v: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithVald(test.args.v) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithVald(test.args.v) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/filter/router/option.go b/pkg/gateway/filter/router/option.go new file mode 100644 index 00000000000..6505c9c83fd --- /dev/null +++ b/pkg/gateway/filter/router/option.go @@ -0,0 +1,42 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "github.com/vdaas/vald/pkg/gateway/filter/handler/rest" +) + +type Option func(*router) + +var ( + defaultOpts = []Option{ + WithTimeout("3s"), + } +) + +func WithHandler(h rest.Handler) Option { + return func(r *router) { + r.handler = h + } +} + +func WithTimeout(timeout string) Option { + return func(r *router) { + r.timeout = timeout + } +} diff --git a/pkg/gateway/filter/router/option_test.go b/pkg/gateway/filter/router/option_test.go new file mode 100644 index 00000000000..e5edd7719df --- /dev/null +++ b/pkg/gateway/filter/router/option_test.go @@ -0,0 +1,252 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "testing" + + "github.com/vdaas/vald/pkg/gateway/filter/handler/rest" + + "go.uber.org/goleak" +) + +func TestWithHandler(t *testing.T) { + type T = interface{} + type args struct { + h rest.Handler + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + h: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + h: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithHandler(test.args.h) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithHandler(test.args.h) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithTimeout(t *testing.T) { + type T = interface{} + type args struct { + timeout string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + timeout: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + timeout: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithTimeout(test.args.timeout) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithTimeout(test.args.timeout) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/filter/router/router.go b/pkg/gateway/filter/router/router.go new file mode 100644 index 00000000000..1720220136f --- /dev/null +++ b/pkg/gateway/filter/router/router.go @@ -0,0 +1,130 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "net/http" + + "github.com/vdaas/vald/internal/net/http/routing" + "github.com/vdaas/vald/pkg/gateway/filter/handler/rest" +) + +type router struct { + handler rest.Handler + timeout string +} + +// New returns REST route&method information from handler interface +func New(opts ...Option) http.Handler { + r := new(router) + + for _, opt := range append(defaultOpts, opts...) { + opt(r) + } + + h := r.handler + + return routing.New( + routing.WithRoutes([]routing.Route{ + { + "Index", + []string{ + http.MethodGet, + }, + "/", + h.Index, + }, + { + "Search", + []string{ + http.MethodPost, + }, + "/search", + h.Search, + }, + { + "Search By ID", + []string{ + http.MethodGet, + }, + "/search/{id}", + h.SearchByID, + }, + { + "Insert", + []string{ + http.MethodPost, + }, + "/insert", + h.Insert, + }, + { + "Multiple Insert", + []string{ + http.MethodPost, + }, + "/insert/multi", + h.MultiInsert, + }, + { + "Update", + []string{ + http.MethodPost, + http.MethodPatch, + http.MethodPut, + }, + "/update", + h.Update, + }, + { + "Multiple Update", + []string{ + http.MethodPost, + http.MethodPatch, + http.MethodPut, + }, + "/update/multi", + h.MultiUpdate, + }, + { + "Remove", + []string{ + http.MethodDelete, + }, + "/delete/{id}", + h.Remove, + }, + { + "Multiple Remove", + []string{ + http.MethodDelete, + http.MethodPost, + }, + "/delete/multi", + h.MultiRemove, + }, + { + "GetObject", + []string{ + http.MethodGet, + }, + "/object/{id}", + h.GetObject, + }, + }...)) +} diff --git a/pkg/gateway/filter/router/router_test.go b/pkg/gateway/filter/router/router_test.go new file mode 100644 index 00000000000..876b9574c48 --- /dev/null +++ b/pkg/gateway/filter/router/router_test.go @@ -0,0 +1,96 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "net/http" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errors" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want http.Handler + } + type test struct { + name string + args args + want want + checkFunc func(want, http.Handler) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got http.Handler) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/service/backup.go b/pkg/gateway/filter/service/backup.go new file mode 100644 index 00000000000..bc50e649047 --- /dev/null +++ b/pkg/gateway/filter/service/backup.go @@ -0,0 +1,138 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + + "github.com/vdaas/vald/apis/grpc/manager/compressor" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" +) + +type Backup interface { + Start(ctx context.Context) (<-chan error, error) + GetObject(ctx context.Context, uuid string) (*payload.Backup_MetaVector, error) + GetLocation(ctx context.Context, uuid string) ([]string, error) + Register(ctx context.Context, vec *payload.Backup_MetaVector) error + RegisterMultiple(ctx context.Context, vecs *payload.Backup_MetaVectors) error + Remove(ctx context.Context, uuid string) error + RemoveMultiple(ctx context.Context, uuids ...string) error +} + +type backup struct { + addr string + client grpc.Client +} + +func NewBackup(opts ...BackupOption) (bu Backup, err error) { + b := new(backup) + for _, opt := range append(defaultBackupOpts, opts...) { + if err := opt(b); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + + return b, nil +} + +func (b *backup) Start(ctx context.Context) (<-chan error, error) { + return b.client.StartConnectionMonitor(ctx) +} + +func (b *backup) GetObject(ctx context.Context, uuid string) (vec *payload.Backup_MetaVector, err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + vec, err = compressor.NewBackupClient(conn).GetVector(ctx, &payload.Backup_GetVector_Request{ + Uuid: uuid, + }, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) GetLocation(ctx context.Context, uuid string) (ipList []string, err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + ips, err := compressor.NewBackupClient(conn).Locations(ctx, &payload.Backup_Locations_Request{ + Uuid: uuid, + }, copts...) + if err != nil { + return nil, err + } + ipList = ips.GetIp() + return + }) + return +} + +func (b *backup) Register(ctx context.Context, vec *payload.Backup_MetaVector) (err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).Register(ctx, vec, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) RegisterMultiple(ctx context.Context, vecs *payload.Backup_MetaVectors) (err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).RegisterMulti(ctx, vecs, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) Remove(ctx context.Context, uuid string) (err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).Remove(ctx, &payload.Backup_Remove_Request{ + Uuid: uuid, + }, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) RemoveMultiple(ctx context.Context, uuids ...string) (err error) { + req := new(payload.Backup_Remove_RequestMulti) + req.Uuids = uuids + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).RemoveMulti(ctx, req, copts...) + if err != nil { + return nil, err + } + return + }) + return +} diff --git a/pkg/gateway/filter/service/backup_option.go b/pkg/gateway/filter/service/backup_option.go new file mode 100644 index 00000000000..3647333b074 --- /dev/null +++ b/pkg/gateway/filter/service/backup_option.go @@ -0,0 +1,42 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import "github.com/vdaas/vald/internal/net/grpc" + +type BackupOption func(b *backup) error + +var ( + defaultBackupOpts = []BackupOption{} +) + +func WithBackupAddr(addr string) BackupOption { + return func(b *backup) error { + b.addr = addr + return nil + } +} + +func WithBackupClient(client grpc.Client) BackupOption { + return func(b *backup) error { + if client != nil { + b.client = client + } + return nil + } +} diff --git a/pkg/gateway/filter/service/backup_option_test.go b/pkg/gateway/filter/service/backup_option_test.go new file mode 100644 index 00000000000..ca7bca08cf7 --- /dev/null +++ b/pkg/gateway/filter/service/backup_option_test.go @@ -0,0 +1,252 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestWithBackupAddr(t *testing.T) { + type T = interface{} + type args struct { + addr string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackupAddr(test.args.addr) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackupAddr(test.args.addr) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithBackupClient(t *testing.T) { + type T = interface{} + type args struct { + client grpc.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackupClient(test.args.client) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackupClient(test.args.client) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/filter/service/backup_test.go b/pkg/gateway/filter/service/backup_test.go new file mode 100644 index 00000000000..2d6c262f692 --- /dev/null +++ b/pkg/gateway/filter/service/backup_test.go @@ -0,0 +1,750 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewBackup(t *testing.T) { + type args struct { + opts []BackupOption + } + type want struct { + wantBu Backup + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Backup, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotBu Backup, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotBu, w.wantBu) { + return errors.Errorf("got = %v, want %v", gotBu, w.wantBu) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotBu, err := NewBackup(test.args.opts...) + if err := test.checkFunc(test.want, gotBu, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + got, err := b.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_GetObject(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + wantVec *payload.Backup_MetaVector + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Backup_MetaVector, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotVec *payload.Backup_MetaVector, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotVec, w.wantVec) { + return errors.Errorf("got = %v, want %v", gotVec, w.wantVec) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + gotVec, err := b.GetObject(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotVec, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_GetLocation(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + wantIpList []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotIpList []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotIpList, w.wantIpList) { + return errors.Errorf("got = %v, want %v", gotIpList, w.wantIpList) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + gotIpList, err := b.GetLocation(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotIpList, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_Register(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Backup_MetaVector + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.Register(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_RegisterMultiple(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Backup_MetaVectors + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.RegisterMultiple(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_Remove(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.Remove(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_RemoveMultiple(t *testing.T) { + type args struct { + ctx context.Context + uuids []string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.RemoveMultiple(test.args.ctx, test.args.uuids...) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/service/doc.go b/pkg/gateway/filter/service/doc.go new file mode 100644 index 00000000000..c13956cbbe3 --- /dev/null +++ b/pkg/gateway/filter/service/doc.go @@ -0,0 +1,18 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service manages the main logic of server. +package service diff --git a/pkg/gateway/filter/service/filter.go b/pkg/gateway/filter/service/filter.go new file mode 100644 index 00000000000..819ee59431a --- /dev/null +++ b/pkg/gateway/filter/service/filter.go @@ -0,0 +1,67 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + + "github.com/vdaas/vald/apis/grpc/filter/egress" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" +) + +type Filter interface { + Start(ctx context.Context) (<-chan error, error) + FilterSearch(context.Context, *payload.Search_Response) (*payload.Search_Response, error) +} + +type filter struct { + client grpc.Client +} + +func NewFilter(opts ...FilterOption) (ef Filter, err error) { + f := new(filter) + for _, opt := range append(defaultFilterOpts, opts...) { + if err := opt(f); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + + return f, nil +} + +func (f *filter) Start(ctx context.Context) (<-chan error, error) { + return f.client.StartConnectionMonitor(ctx) +} + +func (f *filter) FilterSearch(ctx context.Context, res *payload.Search_Response) (*payload.Search_Response, error) { + var rerr error + f.client.Range(ctx, + func(ctx context.Context, addr string, conn *grpc.ClientConn, copts ...grpc.CallOption) error { + r, err := egress.NewEgressFilterClient(conn).Filter(ctx, res, copts...) + if err != nil { + rerr = errors.Wrap(rerr, err.Error()) + } else { + res = r + } + return nil + }) + + return res, rerr +} diff --git a/pkg/gateway/filter/service/filter_option.go b/pkg/gateway/filter/service/filter_option.go new file mode 100644 index 00000000000..de11d286d22 --- /dev/null +++ b/pkg/gateway/filter/service/filter_option.go @@ -0,0 +1,35 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import "github.com/vdaas/vald/internal/net/grpc" + +type FilterOption func(f *filter) error + +var ( + defaultFilterOpts = []FilterOption{} +) + +func WithFilterClient(client grpc.Client) FilterOption { + return func(f *filter) error { + if client != nil { + f.client = client + } + return nil + } +} diff --git a/pkg/gateway/filter/service/filter_option_test.go b/pkg/gateway/filter/service/filter_option_test.go new file mode 100644 index 00000000000..80e30f9c0d3 --- /dev/null +++ b/pkg/gateway/filter/service/filter_option_test.go @@ -0,0 +1,139 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestWithFilterClient(t *testing.T) { + type T = interface{} + type args struct { + client grpc.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithFilterClient(test.args.client) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithFilterClient(test.args.client) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/filter/service/filter_test.go b/pkg/gateway/filter/service/filter_test.go new file mode 100644 index 00000000000..e03f77c8214 --- /dev/null +++ b/pkg/gateway/filter/service/filter_test.go @@ -0,0 +1,283 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewFilter(t *testing.T) { + type args struct { + opts []FilterOption + } + type want struct { + wantEf Filter + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Filter, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotEf Filter, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotEf, w.wantEf) { + return errors.Errorf("got = %v, want %v", gotEf, w.wantEf) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotEf, err := NewFilter(test.args.opts...) + if err := test.checkFunc(test.want, gotEf, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_filter_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + client grpc.Client + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + f := &filter{ + client: test.fields.client, + } + + got, err := f.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_filter_FilterSearch(t *testing.T) { + type args struct { + ctx context.Context + res *payload.Search_Response + } + type fields struct { + client grpc.Client + } + type want struct { + want *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + res: nil, + }, + fields: fields { + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + res: nil, + }, + fields: fields { + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + f := &filter{ + client: test.fields.client, + } + + got, err := f.FilterSearch(test.args.ctx, test.args.res) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/service/gateway.go b/pkg/gateway/filter/service/gateway.go new file mode 100644 index 00000000000..06469551ad2 --- /dev/null +++ b/pkg/gateway/filter/service/gateway.go @@ -0,0 +1,119 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "context" + "reflect" + "sync/atomic" + + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/internal/client/discoverer" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/net/grpc" +) + +type Gateway interface { + Start(ctx context.Context) (<-chan error, error) + GetAgentCount(ctx context.Context) int + Do(ctx context.Context, + f func(ctx context.Context, tgt string, ac agent.AgentClient, copts ...grpc.CallOption) error) error + DoMulti(ctx context.Context, num int, + f func(ctx context.Context, tgt string, ac agent.AgentClient, copts ...grpc.CallOption) error) error + BroadCast(ctx context.Context, + f func(ctx context.Context, tgt string, ac agent.AgentClient, copts ...grpc.CallOption) error) error +} + +type gateway struct { + client discoverer.Client + eg errgroup.Group +} + +func NewGateway(opts ...GWOption) (gw Gateway, err error) { + g := new(gateway) + for _, opt := range append(defaultGWOpts, opts...) { + if err := opt(g); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + return g, nil +} + +func (g *gateway) Start(ctx context.Context) (<-chan error, error) { + return g.client.Start(ctx) +} + +func (g *gateway) BroadCast(ctx context.Context, + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error) (err error) { + return g.client.GetClient().RangeConcurrent(ctx, -1, func(ctx context.Context, + addr string, conn *grpc.ClientConn, copts ...grpc.CallOption) (err error) { + select { + case <-ctx.Done(): + return nil + default: + err = f(ctx, addr, agent.NewAgentClient(conn), copts...) + if err != nil { + log.Debug(addr, err) + return err + } + } + return nil + }) +} + +func (g *gateway) Do(ctx context.Context, + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error) (err error) { + addr := g.client.GetAddrs(ctx)[0] + _, err = g.client.GetClient().Do(ctx, addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + return nil, f(ctx, addr, agent.NewAgentClient(conn), copts...) + }) + return err +} + +func (g *gateway) DoMulti(ctx context.Context, num int, + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error) (err error) { + var cur uint32 = 0 + limit := uint32(num) + addrs := g.client.GetAddrs(ctx) + log.Debug("DoMulti", addrs) + err = g.client.GetClient().OrderedRange(ctx, addrs, func(ictx context.Context, + addr string, + conn *grpc.ClientConn, + copts ...grpc.CallOption) (err error) { + if atomic.LoadUint32(&cur) < limit { + err = f(ictx, addr, agent.NewAgentClient(conn), copts...) + if err != nil { + log.Debug(addr, err) + return err + } + atomic.AddUint32(&cur, 1) + } + return nil + }) + if err != nil && cur < limit { + return err + } + return nil +} + +func (g *gateway) GetAgentCount(ctx context.Context) int { + return len(g.client.GetAddrs(ctx)) +} diff --git a/pkg/gateway/filter/service/gateway_option.go b/pkg/gateway/filter/service/gateway_option.go new file mode 100644 index 00000000000..b385031d804 --- /dev/null +++ b/pkg/gateway/filter/service/gateway_option.go @@ -0,0 +1,49 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "github.com/vdaas/vald/internal/client/discoverer" + "github.com/vdaas/vald/internal/errgroup" +) + +type GWOption func(g *gateway) error + +var ( + defaultGWOpts = []GWOption{ + WithErrGroup(errgroup.Get()), + } +) + +func WithDiscoverer(c discoverer.Client) GWOption { + return func(g *gateway) error { + if c != nil { + g.client = c + } + return nil + } +} + +func WithErrGroup(eg errgroup.Group) GWOption { + return func(g *gateway) error { + if eg != nil { + g.eg = eg + } + return nil + } +} diff --git a/pkg/gateway/filter/service/gateway_option_test.go b/pkg/gateway/filter/service/gateway_option_test.go new file mode 100644 index 00000000000..7a4c8cea021 --- /dev/null +++ b/pkg/gateway/filter/service/gateway_option_test.go @@ -0,0 +1,253 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/client/discoverer" + "github.com/vdaas/vald/internal/errgroup" + + "go.uber.org/goleak" +) + +func TestWithDiscoverer(t *testing.T) { + type T = interface{} + type args struct { + c discoverer.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithDiscoverer(test.args.c) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithDiscoverer(test.args.c) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithErrGroup(t *testing.T) { + type T = interface{} + type args struct { + eg errgroup.Group + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithErrGroup(test.args.eg) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithErrGroup(test.args.eg) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/filter/service/gateway_test.go b/pkg/gateway/filter/service/gateway_test.go new file mode 100644 index 00000000000..b2592a62b00 --- /dev/null +++ b/pkg/gateway/filter/service/gateway_test.go @@ -0,0 +1,563 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "context" + "reflect" + "testing" + + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/internal/client/discoverer" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewGateway(t *testing.T) { + type args struct { + opts []GWOption + } + type want struct { + wantGw Gateway + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Gateway, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotGw Gateway, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotGw, w.wantGw) { + return errors.Errorf("got = %v, want %v", gotGw, w.wantGw) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotGw, err := NewGateway(test.args.opts...) + if err := test.checkFunc(test.want, gotGw, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + got, err := g.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_BroadCast(t *testing.T) { + type args struct { + ctx context.Context + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + err := g.BroadCast(test.args.ctx, test.args.f) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_Do(t *testing.T) { + type args struct { + ctx context.Context + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + err := g.Do(test.args.ctx, test.args.f) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_DoMulti(t *testing.T) { + type args struct { + ctx context.Context + num int + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + num: 0, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + num: 0, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + err := g.DoMulti(test.args.ctx, test.args.num, test.args.f) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_GetAgentCount(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + want int + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got int) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + got := g.GetAgentCount(test.args.ctx) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/service/meta.go b/pkg/gateway/filter/service/meta.go new file mode 100644 index 00000000000..1ca8f43ffb6 --- /dev/null +++ b/pkg/gateway/filter/service/meta.go @@ -0,0 +1,490 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service provides meta service +package service + +import ( + "context" + "reflect" + + gmeta "github.com/vdaas/vald/apis/grpc/meta" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/status" + "github.com/vdaas/vald/internal/observability/trace" +) + +type Meta interface { + Start(ctx context.Context) (<-chan error, error) + Exists(context.Context, string) (bool, error) + GetMeta(context.Context, string) (string, error) + GetMetas(context.Context, ...string) ([]string, error) + GetUUID(context.Context, string) (string, error) + GetUUIDs(context.Context, ...string) ([]string, error) + SetUUIDandMeta(context.Context, string, string) error + SetUUIDandMetas(context.Context, map[string]string) error + DeleteMeta(context.Context, string) (string, error) + DeleteMetas(context.Context, ...string) ([]string, error) + DeleteUUID(context.Context, string) (string, error) + DeleteUUIDs(context.Context, ...string) ([]string, error) +} + +type meta struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string +} + +const ( + uuidCacheKeyPref = "uuid-" + metaCacheKeyPref = "meta-" +) + +func NewMeta(opts ...MetaOption) (mi Meta, err error) { + m := new(meta) + for _, opt := range append(defaultMetaOpts, opts...) { + if err = opt(m); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + if m.enableCache { + if m.cache == nil { + m.cache, err = cache.New( + cache.WithExpireDuration(m.expireDuration), + cache.WithExpireCheckDuration(m.expireCheckDuration), + ) + if err != nil { + return nil, err + } + } + } + + return m, nil +} + +func (m *meta) Start(ctx context.Context) (<-chan error, error) { + if m.enableCache && m.cache != nil { + m.cache.Start(ctx) + } + return m.client.StartConnectionMonitor(ctx) +} + +func (m *meta) Exists(ctx context.Context, meta string) (bool, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.Exists") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + _, ok := m.cache.Get(uuidCacheKeyPref + meta) + if ok { + return true, nil + } + } + key, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + key, err := gmeta.NewMetaClient(conn).GetMetaInverse(ctx, &payload.Meta_Val{ + Val: meta, + }, copts...) + if err != nil { + if status.Code(err) == status.NotFound { + return "", nil + } + return nil, err + } + return key.GetKey(), nil + }) + if err != nil { + return false, err + } + + k := key.(string) + if k == "" { + return false, nil + } + + if m.enableCache { + m.cache.Set(uuidCacheKeyPref+meta, k) + m.cache.Set(metaCacheKeyPref+k, meta) + } + return true, nil +} + +func (m *meta) GetMeta(ctx context.Context, uuid string) (v string, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetMeta") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + data, ok := m.cache.Get(metaCacheKeyPref + uuid) + if ok { + return data.(string), nil + } + } + val, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + val, err := gmeta.NewMetaClient(conn).GetMeta(ctx, &payload.Meta_Key{ + Key: uuid, + }, copts...) + if err != nil { + return nil, err + } + return val.GetVal(), nil + }) + if err != nil { + return "", err + } + v = val.(string) + + if m.enableCache { + m.cache.Set(metaCacheKeyPref+uuid, v) + m.cache.Set(uuidCacheKeyPref+v, uuid) + } + return v, nil +} + +func (m *meta) GetMetas(ctx context.Context, uuids ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetMetas") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + metas, ok := func() (metas []string, ok bool) { + for _, uuid := range uuids { + data, ok := m.cache.Get(metaCacheKeyPref + uuid) + if !ok { + return nil, false + } + metas = append(metas, data.(string)) + } + return metas, true + }() + if ok { + return metas, nil + } + } + vals, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + vals, err := gmeta.NewMetaClient(conn).GetMetas(ctx, &payload.Meta_Keys{ + Keys: uuids, + }, copts...) + if vals != nil { + return vals.GetVals(), err + } + return nil, err + }) + if vals != nil { + vs, ok := vals.([]string) + if ok { + if m.enableCache { + for i, v := range vs { + uuid := uuids[i] + m.cache.Set(metaCacheKeyPref+uuid, v) + m.cache.Set(uuidCacheKeyPref+v, uuid) + } + } + return vs, err + } + } + return nil, err +} + +func (m *meta) GetUUID(ctx context.Context, meta string) (k string, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetUUID") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + data, ok := m.cache.Get(uuidCacheKeyPref + meta) + if ok { + return data.(string), nil + } + } + key, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + key, err := gmeta.NewMetaClient(conn).GetMetaInverse(ctx, &payload.Meta_Val{ + Val: meta, + }, copts...) + if err != nil { + return nil, err + } + return key.GetKey(), nil + }) + if err != nil { + return "", err + } + + k = key.(string) + if m.enableCache { + m.cache.Set(uuidCacheKeyPref+meta, k) + m.cache.Set(metaCacheKeyPref+k, meta) + } + return k, nil +} + +func (m *meta) GetUUIDs(ctx context.Context, metas ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetUUIDs") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + uuids, ok := func() (uuids []string, ok bool) { + for _, meta := range metas { + data, ok := m.cache.Get(uuidCacheKeyPref + meta) + if !ok { + return nil, false + } + uuids = append(uuids, data.(string)) + } + return uuids, true + }() + if ok { + return uuids, nil + } + } + keys, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + keys, err := gmeta.NewMetaClient(conn).GetMetasInverse(ctx, &payload.Meta_Vals{ + Vals: metas, + }, copts...) + if keys != nil { + return keys.GetKeys(), err + } + return nil, err + }) + if keys != nil { + ks, ok := keys.([]string) + if ok { + if m.enableCache { + for i, k := range ks { + meta := metas[i] + m.cache.Set(uuidCacheKeyPref+meta, k) + m.cache.Set(metaCacheKeyPref+k, meta) + } + } + return ks, err + } + } + return nil, err +} + +func (m *meta) SetUUIDandMeta(ctx context.Context, uuid, meta string) (err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.SetUUIDandMeta") + defer func() { + if span != nil { + span.End() + } + }() + + _, err = m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + _, err := gmeta.NewMetaClient(conn).SetMeta(ctx, &payload.Meta_KeyVal{ + Key: uuid, + Val: meta, + }, copts...) + + return nil, err + }) + if err != nil { + return err + } + + if m.enableCache { + m.cache.Set(uuidCacheKeyPref+meta, uuid) + m.cache.Set(metaCacheKeyPref+uuid, meta) + } + return nil +} + +func (m *meta) SetUUIDandMetas(ctx context.Context, kvs map[string]string) (err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.SetUUIDandMetas") + defer func() { + if span != nil { + span.End() + } + }() + + data := make([]*payload.Meta_KeyVal, 0, len(kvs)) + for uuid, meta := range kvs { + data = append(data, &payload.Meta_KeyVal{ + Key: uuid, + Val: meta, + }) + } + _, err = m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + _, err := gmeta.NewMetaClient(conn).SetMetas(ctx, &payload.Meta_KeyVals{ + Kvs: data, + }, copts...) + + return nil, err + }) + if err != nil { + return err + } + + if m.enableCache { + for uuid, meta := range kvs { + m.cache.Set(uuidCacheKeyPref+meta, uuid) + m.cache.Set(metaCacheKeyPref+uuid, meta) + } + } + return nil +} + +func (m *meta) DeleteMeta(ctx context.Context, uuid string) (v string, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteMeta") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + meta, ok := m.cache.GetAndDelete(metaCacheKeyPref + uuid) + if ok { + m.cache.Delete(uuidCacheKeyPref + meta.(string)) + } + } + val, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + val, err := gmeta.NewMetaClient(conn).DeleteMeta(ctx, &payload.Meta_Key{ + Key: uuid, + }, copts...) + if err != nil { + return nil, err + } + return val.GetVal(), nil + }) + if err != nil { + return "", err + } + return val.(string), nil +} + +func (m *meta) DeleteMetas(ctx context.Context, uuids ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteMetas") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + for _, uuid := range uuids { + meta, ok := m.cache.GetAndDelete(metaCacheKeyPref + uuid) + if ok { + m.cache.Delete(uuidCacheKeyPref + meta.(string)) + } + } + } + vals, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + vals, err := gmeta.NewMetaClient(conn).DeleteMetas(ctx, &payload.Meta_Keys{ + Keys: uuids, + }, copts...) + if err != nil { + return nil, err + } + return vals.GetVals(), nil + }) + if err != nil { + return nil, err + } + return vals.([]string), nil +} + +func (m *meta) DeleteUUID(ctx context.Context, meta string) (string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteUUID") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + uuid, ok := m.cache.GetAndDelete(uuidCacheKeyPref + meta) + if ok { + m.cache.Delete(metaCacheKeyPref + uuid.(string)) + } + } + key, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + key, err := gmeta.NewMetaClient(conn).DeleteMetaInverse(ctx, &payload.Meta_Val{ + Val: meta, + }, copts...) + if err != nil { + return nil, err + } + return key.GetKey(), nil + }) + if err != nil { + return "", err + } + return key.(string), nil +} + +func (m *meta) DeleteUUIDs(ctx context.Context, metas ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteUUIDs") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + for _, meta := range metas { + uuid, ok := m.cache.GetAndDelete(uuidCacheKeyPref + meta) + if ok { + m.cache.Delete(metaCacheKeyPref + uuid.(string)) + } + } + } + keys, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + keys, err := gmeta.NewMetaClient(conn).DeleteMetasInverse(ctx, &payload.Meta_Vals{ + Vals: metas, + }, copts...) + if err != nil { + return nil, err + } + return keys.GetKeys(), nil + }) + if err != nil { + return nil, err + } + return keys.([]string), nil +} diff --git a/pkg/gateway/filter/service/meta_option.go b/pkg/gateway/filter/service/meta_option.go new file mode 100644 index 00000000000..a5014a18687 --- /dev/null +++ b/pkg/gateway/filter/service/meta_option.go @@ -0,0 +1,97 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "fmt" + + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/timeutil" +) + +type MetaOption func(m *meta) error + +var ( + defaultMetaOpts = []MetaOption{ + WithMetaCacheEnabled(true), + WithMetaCacheExpireDuration("30m"), + WithMetaCacheExpiredCheckDuration("2m"), + } +) + +func WithMetaAddr(addr string) MetaOption { + return func(m *meta) error { + m.addr = addr + return nil + } +} + +func WithMetaHostPort(host string, port int) MetaOption { + return func(m *meta) error { + m.addr = fmt.Sprintf("%s:%d", host, port) + return nil + } +} + +func WithMetaClient(client grpc.Client) MetaOption { + return func(m *meta) error { + if client != nil { + m.client = client + } + return nil + } +} + +func WithMetaCacheEnabled(flg bool) MetaOption { + return func(m *meta) error { + m.enableCache = flg + return nil + } +} + +func WithMetaCache(c cache.Cache) MetaOption { + return func(m *meta) error { + if c != nil { + m.cache = c + } + return nil + } +} + +func WithMetaCacheExpireDuration(dur string) MetaOption { + return func(m *meta) error { + _, err := timeutil.Parse(dur) + if err != nil { + return err + } + m.expireDuration = dur + return nil + } +} + +func WithMetaCacheExpiredCheckDuration(dur string) MetaOption { + return func(m *meta) error { + _, err := timeutil.Parse(dur) + if err != nil { + return err + } + m.expireCheckDuration = dur + return nil + } +} diff --git a/pkg/gateway/filter/service/meta_option_test.go b/pkg/gateway/filter/service/meta_option_test.go new file mode 100644 index 00000000000..4aa31369999 --- /dev/null +++ b/pkg/gateway/filter/service/meta_option_test.go @@ -0,0 +1,821 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestWithMetaAddr(t *testing.T) { + type T = interface{} + type args struct { + addr string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaAddr(test.args.addr) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaAddr(test.args.addr) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaHostPort(t *testing.T) { + type T = interface{} + type args struct { + host string + port int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + host: "", + port: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + host: "", + port: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaHostPort(test.args.host, test.args.port) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaHostPort(test.args.host, test.args.port) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaClient(t *testing.T) { + type T = interface{} + type args struct { + client grpc.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaClient(test.args.client) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaClient(test.args.client) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCacheEnabled(t *testing.T) { + type T = interface{} + type args struct { + flg bool + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + flg: false, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + flg: false, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCacheEnabled(test.args.flg) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCacheEnabled(test.args.flg) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCache(t *testing.T) { + type T = interface{} + type args struct { + c cache.Cache + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCache(test.args.c) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCache(test.args.c) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCacheExpireDuration(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCacheExpireDuration(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCacheExpireDuration(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCacheExpiredCheckDuration(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCacheExpiredCheckDuration(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCacheExpiredCheckDuration(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/filter/service/meta_test.go b/pkg/gateway/filter/service/meta_test.go new file mode 100644 index 00000000000..c2d0835a8ac --- /dev/null +++ b/pkg/gateway/filter/service/meta_test.go @@ -0,0 +1,1429 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service provides meta service +package service + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewMeta(t *testing.T) { + type args struct { + opts []MetaOption + } + type want struct { + wantMi Meta + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Meta, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotMi Meta, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotMi, w.wantMi) { + return errors.Errorf("got = %v, want %v", gotMi, w.wantMi) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotMi, err := NewMeta(test.args.opts...) + if err := test.checkFunc(test.want, gotMi, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_Exists(t *testing.T) { + type args struct { + ctx context.Context + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want bool + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, bool, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got bool, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.Exists(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetMeta(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + wantV string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotV string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotV, w.wantV) { + return errors.Errorf("got = %v, want %v", gotV, w.wantV) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + gotV, err := m.GetMeta(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotV, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetMetas(t *testing.T) { + type args struct { + ctx context.Context + uuids []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.GetMetas(test.args.ctx, test.args.uuids...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetUUID(t *testing.T) { + type args struct { + ctx context.Context + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + wantK string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotK string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotK, w.wantK) { + return errors.Errorf("got = %v, want %v", gotK, w.wantK) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + gotK, err := m.GetUUID(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, gotK, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetUUIDs(t *testing.T) { + type args struct { + ctx context.Context + metas []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.GetUUIDs(test.args.ctx, test.args.metas...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_SetUUIDandMeta(t *testing.T) { + type args struct { + ctx context.Context + uuid string + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + err := m.SetUUIDandMeta(test.args.ctx, test.args.uuid, test.args.meta) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_SetUUIDandMetas(t *testing.T) { + type args struct { + ctx context.Context + kvs map[string]string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + kvs: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + kvs: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + err := m.SetUUIDandMetas(test.args.ctx, test.args.kvs) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteMeta(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + wantV string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotV string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotV, w.wantV) { + return errors.Errorf("got = %v, want %v", gotV, w.wantV) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + gotV, err := m.DeleteMeta(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotV, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteMetas(t *testing.T) { + type args struct { + ctx context.Context + uuids []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.DeleteMetas(test.args.ctx, test.args.uuids...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteUUID(t *testing.T) { + type args struct { + ctx context.Context + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.DeleteUUID(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteUUIDs(t *testing.T) { + type args struct { + ctx context.Context + metas []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.DeleteUUIDs(test.args.ctx, test.args.metas...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/filter/usecase/vald.go b/pkg/gateway/filter/usecase/vald.go new file mode 100644 index 00000000000..7ff004c5e61 --- /dev/null +++ b/pkg/gateway/filter/usecase/vald.go @@ -0,0 +1,328 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package usecase + +import ( + "context" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/internal/client/discoverer" + iconf "github.com/vdaas/vald/internal/config" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/metric" + "github.com/vdaas/vald/internal/observability" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/internal/servers/server" + "github.com/vdaas/vald/internal/servers/starter" + "github.com/vdaas/vald/pkg/gateway/filter/config" + handler "github.com/vdaas/vald/pkg/gateway/filter/handler/grpc" + "github.com/vdaas/vald/pkg/gateway/filter/handler/rest" + "github.com/vdaas/vald/pkg/gateway/filter/router" + "github.com/vdaas/vald/pkg/gateway/filter/service" +) + +type run struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup +} + +func New(cfg *config.Data) (r runner.Runner, err error) { + eg := errgroup.Get() + + var ( + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + ) + + if addrs := cfg.Gateway.BackupManager.Client.Addrs; len(addrs) == 0 { + return nil, errors.ErrInvalidBackupConfig + } + + backupClientOptions := append( + cfg.Gateway.BackupManager.Client.Opts(), + grpc.WithErrGroup(eg), + ) + + discovererClientOptions := append( + cfg.Gateway.Discoverer.Client.Opts(), + grpc.WithErrGroup(eg), + ) + + metadataClientOptions := append( + cfg.Gateway.Meta.Client.Opts(), + grpc.WithErrGroup(eg), + ) + + var obs observability.Observability + if cfg.Observability.Enabled { + obs, err = observability.NewWithConfig(cfg.Observability) + if err != nil { + return nil, err + } + backupClientOptions = append( + backupClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + discovererClientOptions = append( + discovererClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + metadataClientOptions = append( + metadataClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + } + + backup, err = service.NewBackup( + service.WithBackupAddr(cfg.Gateway.BackupManager.Client.Addrs[0]), + service.WithBackupClient( + grpc.New(backupClientOptions...), + ), + ) + if err != nil { + return nil, err + } + client, err := discoverer.New( + discoverer.WithAutoConnect(true), + discoverer.WithName(cfg.Gateway.AgentName), + discoverer.WithNamespace(cfg.Gateway.AgentNamespace), + discoverer.WithPort(cfg.Gateway.AgentPort), + discoverer.WithServiceDNSARecord(cfg.Gateway.AgentDNS), + discoverer.WithDiscovererClient(grpc.New(discovererClientOptions...)), + discoverer.WithDiscovererHostPort( + cfg.Gateway.Discoverer.Host, + cfg.Gateway.Discoverer.Port, + ), + discoverer.WithDiscoverDuration(cfg.Gateway.Discoverer.Duration), + discoverer.WithOptions(cfg.Gateway.Discoverer.AgentClient.Opts()...), + discoverer.WithNodeName(cfg.Gateway.NodeName), + ) + if err != nil { + return nil, err + } + gateway, err = service.NewGateway( + service.WithErrGroup(eg), + service.WithDiscoverer(client), + ) + if err != nil { + return nil, err + } + + if addrs := cfg.Gateway.Meta.Client.Addrs; len(addrs) == 0 { + return nil, errors.ErrInvalidMetaDataConfig + } + metadata, err = service.NewMeta( + service.WithMetaAddr(cfg.Gateway.Meta.Client.Addrs[0]), + service.WithMetaClient( + grpc.New(metadataClientOptions...), + ), + service.WithMetaCacheEnabled(cfg.Gateway.Meta.EnableCache), + service.WithMetaCacheExpireDuration(cfg.Gateway.Meta.CacheExpiration), + service.WithMetaCacheExpiredCheckDuration(cfg.Gateway.Meta.ExpiredCacheCheckDuration), + ) + if err != nil { + return nil, err + } + + ef := cfg.Gateway.EgressFilter + if ef != nil && + ef.Client != nil && + ef.Client.Addrs != nil && + len(ef.Client.Addrs) != 0 { + egressFilterClientOptions := append( + ef.Client.Opts(), + grpc.WithErrGroup(eg), + ) + if cfg.Observability.Enabled { + egressFilterClientOptions = append( + egressFilterClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + } + filter, err = service.NewFilter( + service.WithFilterClient( + grpc.New(egressFilterClientOptions...), + ), + ) + } + + v := handler.New( + handler.WithGateway(gateway), + handler.WithBackup(backup), + handler.WithMeta(metadata), + handler.WithFilters(filter), + handler.WithErrGroup(eg), + handler.WithReplicationCount(cfg.Gateway.IndexReplica), + handler.WithStreamConcurrency(cfg.Server.GetGRPCStreamConcurrency()), + ) + + grpcServerOptions := []server.Option{ + server.WithGRPCRegistFunc(func(srv *grpc.Server) { + vald.RegisterValdServer(srv, v) + }), + server.WithPreStopFunction(func() error { + // TODO notify another gateway and scheduler + return nil + }), + } + + if cfg.Observability.Enabled { + grpcServerOptions = append( + grpcServerOptions, + server.WithGRPCOption( + grpc.StatsHandler(metric.NewServerHandler()), + ), + ) + } + + srv, err := starter.New( + starter.WithConfig(cfg.Server), + starter.WithREST(func(sc *iconf.Server) []server.Option { + return []server.Option{ + server.WithHTTPHandler( + router.New( + router.WithHandler( + rest.New( + rest.WithVald(v), + ), + ), + ), + ), + } + }), + starter.WithGRPC(func(sc *iconf.Server) []server.Option { + return grpcServerOptions + }), + // TODO add GraphQL handler + ) + if err != nil { + return nil, err + } + + return &run{ + eg: eg, + cfg: cfg, + server: srv, + observability: obs, + filter: filter, + gateway: gateway, + metadata: metadata, + backup: backup, + }, nil +} + +func (r *run) PreStart(ctx context.Context) error { + if r.observability != nil { + return r.observability.PreStart(ctx) + } + return nil +} + +func (r *run) Start(ctx context.Context) (<-chan error, error) { + ech := make(chan error, 6) + var bech, fech, mech, gech, sech, oech <-chan error + var err error + if r.observability != nil { + oech = r.observability.Start(ctx) + } + if r.backup != nil { + bech, err = r.backup.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + if r.filter != nil { + fech, err = r.filter.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + if r.metadata != nil { + mech, err = r.metadata.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + if r.gateway != nil { + gech, err = r.gateway.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + sech = r.server.ListenAndServe(ctx) + r.eg.Go(safety.RecoverFunc(func() (err error) { + defer close(ech) + for { + select { + case <-ctx.Done(): + return ctx.Err() + case err = <-oech: + case err = <-bech: + case err = <-fech: + case err = <-gech: + case err = <-mech: + case err = <-sech: + } + if err != nil { + select { + case <-ctx.Done(): + return ctx.Err() + case ech <- err: + } + } + } + })) + return ech, nil +} + +func (r *run) PreStop(ctx context.Context) error { + return nil +} + +func (r *run) Stop(ctx context.Context) error { + if r.observability != nil { + r.observability.Stop(ctx) + } + return r.server.Shutdown(ctx) +} + +func (r *run) PostStop(ctx context.Context) error { + return nil +} diff --git a/pkg/gateway/filter/usecase/vald_test.go b/pkg/gateway/filter/usecase/vald_test.go new file mode 100644 index 00000000000..b6b27a9db97 --- /dev/null +++ b/pkg/gateway/filter/usecase/vald_test.go @@ -0,0 +1,672 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package usecase + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/observability" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/servers/starter" + "github.com/vdaas/vald/pkg/gateway/filter/config" + "github.com/vdaas/vald/pkg/gateway/filter/service" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + cfg *config.Data + } + type want struct { + wantR runner.Runner + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, runner.Runner, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotR runner.Runner, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotR, w.wantR) { + return errors.Errorf("got = %v, want %v", gotR, w.wantR) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + cfg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + cfg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotR, err := New(test.args.cfg) + if err := test.checkFunc(test.want, gotR, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PreStart(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PreStart(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + got, err := r.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PreStop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PreStop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_Stop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.Stop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PostStop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PostStop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/README.md b/pkg/gateway/lb/README.md new file mode 100755 index 00000000000..9b8d2e1af5c --- /dev/null +++ b/pkg/gateway/lb/README.md @@ -0,0 +1 @@ +# server sample diff --git a/pkg/gateway/lb/config/config.go b/pkg/gateway/lb/config/config.go new file mode 100644 index 00000000000..6e4109fdabd --- /dev/null +++ b/pkg/gateway/lb/config/config.go @@ -0,0 +1,148 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package setting stores all server application settings +package config + +import ( + "github.com/vdaas/vald/internal/config" +) + +type GlobalConfig = config.GlobalConfig + +// Config represent a application setting data content (config.yaml). +// In K8s environment, this configuration is stored in K8s ConfigMap. +type Data struct { + config.GlobalConfig `json:",inline" yaml:",inline"` + + // Server represent all server configurations + Server *config.Servers `json:"server_config" yaml:"server_config"` + + // Observability represent observability configurations + Observability *config.Observability `json:"observability" yaml:"observability"` + + // Gateway represent agent gateway service configuration + Gateway *config.Gateway `json:"gateway" yaml:"gateway"` +} + +func NewConfig(path string) (cfg *Data, err error) { + err = config.Read(path, &cfg) + + if err != nil { + return nil, err + } + + if cfg != nil { + cfg.Bind() + } + + if cfg.Server != nil { + cfg.Server = cfg.Server.Bind() + } + + if cfg.Observability != nil { + cfg.Observability = cfg.Observability.Bind() + } + + if cfg.Gateway != nil { + cfg.Gateway = cfg.Gateway.Bind() + } + + return cfg, nil +} + +// func FakeData() { +// d := Data{ +// Version: "v0.0.1", +// Server: &config.Servers{ +// Servers: []*config.Server{ +// { +// Name: "agent-rest", +// Host: "127.0.0.1", +// Port: 8080, +// Mode: "REST", +// ProbeWaitTime: "3s", +// ShutdownDuration: "5s", +// HandlerTimeout: "5s", +// IdleTimeout: "2s", +// ReadHeaderTimeout: "1s", +// ReadTimeout: "1s", +// WriteTimeout: "1s", +// }, +// { +// Name: "agent-grpc", +// Host: "127.0.0.1", +// Port: 8082, +// Mode: "GRPC", +// }, +// }, +// MetricsServers: []*config.Server{ +// { +// Name: "pprof", +// Host: "127.0.0.1", +// Port: 6060, +// Mode: "REST", +// ProbeWaitTime: "3s", +// ShutdownDuration: "5s", +// HandlerTimeout: "5s", +// IdleTimeout: "2s", +// ReadHeaderTimeout: "1s", +// ReadTimeout: "1s", +// WriteTimeout: "1s", +// }, +// }, +// HealthCheckServers: []*config.Server{ +// { +// Name: "livenesss", +// Host: "127.0.0.1", +// Port: 3000, +// }, +// { +// Name: "readiness", +// Host: "127.0.0.1", +// Port: 3001, +// }, +// }, +// StartUpStrategy: []string{ +// "livenesss", +// "pprof", +// "agent-grpc", +// "agent-rest", +// "readiness", +// }, +// ShutdownStrategy: []string{ +// "readiness", +// "agent-rest", +// "agent-grpc", +// "pprof", +// "livenesss", +// }, +// FullShutdownDuration: "30s", +// TLS: &config.TLS{ +// Enabled: false, +// Cert: "/path/to/cert", +// Key: "/path/to/key", +// CA: "/path/to/ca", +// }, +// }, +// Gateway: &config.Gateway{ +// AgentPort: 8080, +// AgentName: "vald-agent", +// BackoffEnabled: false,, +// }, +// } +// fmt.Println(config.ToRawYaml(d)) +// } diff --git a/pkg/gateway/lb/config/config_test.go b/pkg/gateway/lb/config/config_test.go new file mode 100644 index 00000000000..e8090717ead --- /dev/null +++ b/pkg/gateway/lb/config/config_test.go @@ -0,0 +1,101 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package setting stores all server application settings +package config + +import ( + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errors" + "go.uber.org/goleak" +) + +func TestNewConfig(t *testing.T) { + type args struct { + path string + } + type want struct { + wantCfg *Data + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, *Data, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCfg *Data, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCfg, w.wantCfg) { + return errors.Errorf("got = %v, want %v", gotCfg, w.wantCfg) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + path: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + path: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotCfg, err := NewConfig(test.args.path) + if err := test.checkFunc(test.want, gotCfg, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/handler/doc.go b/pkg/gateway/lb/handler/doc.go new file mode 100644 index 00000000000..86b6d1869df --- /dev/null +++ b/pkg/gateway/lb/handler/doc.go @@ -0,0 +1,17 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package handler diff --git a/pkg/gateway/lb/handler/grpc/checklist.go b/pkg/gateway/lb/handler/grpc/checklist.go new file mode 100644 index 00000000000..1d3cdc4b476 --- /dev/null +++ b/pkg/gateway/lb/handler/grpc/checklist.go @@ -0,0 +1,141 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package grpc + +import ( + "sync" + "sync/atomic" + "unsafe" +) + +type checkList struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int +} + +type readOnlyCheckList struct { + m map[string]*entryCheckList + amended bool +} + +var expungedCheckList = unsafe.Pointer(new(struct{})) + +type entryCheckList struct { + p unsafe.Pointer +} + +func (m *checkList) Exists(key string) bool { + read, _ := m.read.Load().(readOnlyCheckList) + e, ok := read.m[key] + if !ok && read.amended { + m.mu.Lock() + read, _ = m.read.Load().(readOnlyCheckList) + e, ok = read.m[key] + if !ok && read.amended { + e, ok = m.dirty[key] + m.missLocked() + } + m.mu.Unlock() + } + if !ok { + return false + } + p := atomic.LoadPointer(&e.p) + if p == nil || p == expungedCheckList { + return false + } + return true +} + +func (m *checkList) Check(key string) { + value := struct{}{} + read, _ := m.read.Load().(readOnlyCheckList) + if e, ok := read.m[key]; ok && e.tryStore(&value) { + return + } + + m.mu.Lock() + read, _ = m.read.Load().(readOnlyCheckList) + if e, ok := read.m[key]; ok { + if e.unexpungeLocked() { + m.dirty[key] = e + } + atomic.StorePointer(&e.p, unsafe.Pointer(&value)) + } else if e, ok := m.dirty[key]; ok { + atomic.StorePointer(&e.p, unsafe.Pointer(&value)) + } else { + if !read.amended { + m.dirtyLocked() + m.read.Store(readOnlyCheckList{m: read.m, amended: true}) + } + m.dirty[key] = &entryCheckList{p: unsafe.Pointer(&value)} + } + m.mu.Unlock() +} + +func (e *entryCheckList) tryStore(i *struct{}) bool { + for { + p := atomic.LoadPointer(&e.p) + if p == expungedCheckList { + return false + } + if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) { + return true + } + } +} + +func (e *entryCheckList) unexpungeLocked() (wasExpunged bool) { + return atomic.CompareAndSwapPointer(&e.p, expungedCheckList, nil) +} + +func (m *checkList) missLocked() { + m.misses++ + if m.misses < len(m.dirty) { + return + } + m.read.Store(readOnlyCheckList{m: m.dirty}) + m.dirty = nil + m.misses = 0 +} + +func (m *checkList) dirtyLocked() { + if m.dirty != nil { + return + } + + read, _ := m.read.Load().(readOnlyCheckList) + m.dirty = make(map[string]*entryCheckList, len(read.m)) + for k, e := range read.m { + if !e.tryExpungeLocked() { + m.dirty[k] = e + } + } +} + +func (e *entryCheckList) tryExpungeLocked() (isExpunged bool) { + p := atomic.LoadPointer(&e.p) + for p == nil { + if atomic.CompareAndSwapPointer(&e.p, nil, expungedCheckList) { + return true + } + p = atomic.LoadPointer(&e.p) + } + return p == expungedCheckList +} diff --git a/pkg/gateway/lb/handler/grpc/checklist_test.go b/pkg/gateway/lb/handler/grpc/checklist_test.go new file mode 100644 index 00000000000..805308ea276 --- /dev/null +++ b/pkg/gateway/lb/handler/grpc/checklist_test.go @@ -0,0 +1,601 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package grpc + +import ( + "reflect" + "sync" + "sync/atomic" + "testing" + "unsafe" + + "github.com/vdaas/vald/internal/errors" +) + +func Test_checkList_Exists(t *testing.T) { + type args struct { + key string + } + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + want bool + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got bool) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + got := m.Exists(test.args.key) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_checkList_Check(t *testing.T) { + type args struct { + key string + } + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + key: "", + }, + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + m.Check(test.args.key) + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + +func Test_entryCheckList_tryStore(t *testing.T) { + type args struct { + i *struct{} + } + type fields struct { + p unsafe.Pointer + } + type want struct { + want bool + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got bool) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + i: struct{}{}, + }, + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + i: struct{}{}, + }, + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + e := &entryCheckList{ + p: test.fields.p, + } + + got := e.tryStore(test.args.i) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_entryCheckList_unexpungeLocked(t *testing.T) { + type fields struct { + p unsafe.Pointer + } + type want struct { + wantWasExpunged bool + } + type test struct { + name string + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want, gotWasExpunged bool) error { + if !reflect.DeepEqual(gotWasExpunged, w.wantWasExpunged) { + return errors.Errorf("got = %v, want %v", gotWasExpunged, w.wantWasExpunged) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + e := &entryCheckList{ + p: test.fields.p, + } + + gotWasExpunged := e.unexpungeLocked() + if err := test.checkFunc(test.want, gotWasExpunged); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_checkList_missLocked(t *testing.T) { + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + } + type test struct { + name string + fields fields + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + m.missLocked() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + +func Test_checkList_dirtyLocked(t *testing.T) { + type fields struct { + mu sync.Mutex + read atomic.Value + dirty map[string]*entryCheckList + misses int + } + type want struct { + } + type test struct { + name string + fields fields + want want + checkFunc func(want) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want) error { + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + mu: sync.Mutex{}, + read: nil, + dirty: nil, + misses: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &checkList{ + mu: test.fields.mu, + read: test.fields.read, + dirty: test.fields.dirty, + misses: test.fields.misses, + } + + m.dirtyLocked() + if err := test.checkFunc(test.want); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + +func Test_entryCheckList_tryExpungeLocked(t *testing.T) { + type fields struct { + p unsafe.Pointer + } + type want struct { + wantIsExpunged bool + } + type test struct { + name string + fields fields + want want + checkFunc func(want, bool) error + beforeFunc func() + afterFunc func() + } + defaultCheckFunc := func(w want, gotIsExpunged bool) error { + if !reflect.DeepEqual(gotIsExpunged, w.wantIsExpunged) { + return errors.Errorf("got = %v, want %v", gotIsExpunged, w.wantIsExpunged) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + fields: fields { + p: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc() + } + if test.afterFunc != nil { + defer test.afterFunc() + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + e := &entryCheckList{ + p: test.fields.p, + } + + gotIsExpunged := e.tryExpungeLocked() + if err := test.checkFunc(test.want, gotIsExpunged); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/handler/grpc/handler.go b/pkg/gateway/lb/handler/grpc/handler.go new file mode 100644 index 00000000000..665fd14a293 --- /dev/null +++ b/pkg/gateway/lb/handler/grpc/handler.go @@ -0,0 +1,851 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "context" + "fmt" + "math" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/kpango/fuid" + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/info" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/status" + "github.com/vdaas/vald/internal/observability/trace" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/pkg/gateway/lb/service" +) + +type server struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int +} + +func New(opts ...Option) vald.ValdServer { + s := new(server) + + for _, opt := range append(defaultOpts, opts...) { + opt(s) + } + return s +} + +func (s *server) Exists(ctx context.Context, meta *payload.Object_ID) (*payload.Object_ID, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Exists") + defer func() { + if span != nil { + span.End() + } + }() + uuid, err := s.metadata.GetUUID(ctx, meta.GetId()) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Exists API meta %s's uuid not found", meta.GetId()), err, meta.GetId(), info.Get()) + } + return &payload.Object_ID{ + Id: uuid, + }, nil +} + +func (s *server) Search(ctx context.Context, req *payload.Search_Request) (res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Search") + defer func() { + if span != nil { + span.End() + } + }() + return s.search(ctx, req.GetConfig(), + func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) { + return ac.Search(ctx, req, copts...) + }) +} + +func (s *server) SearchByID(ctx context.Context, req *payload.Search_IDRequest) ( + res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.SearchByID") + defer func() { + if span != nil { + span.End() + } + }() + metaID := req.GetId() + req.Id, err = s.metadata.GetUUID(ctx, metaID) + if err != nil { + req.Id = metaID + log.Errorf("error at SearchByID\t%v", err) + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("SearchByID API meta %s's uuid not found", metaID), err, req, info.Get()) + } + return s.search(ctx, req.GetConfig(), + func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) { + return ac.SearchByID(ctx, req, copts...) + }) +} + +func (s *server) search(ctx context.Context, cfg *payload.Search_Config, + f func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error)) ( + res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.search") + defer func() { + if span != nil { + span.End() + } + }() + maxDist := uint32(math.MaxUint32) + num := int(cfg.GetNum()) + res = new(payload.Search_Response) + res.Results = make([]*payload.Object_Distance, 0, s.gateway.GetAgentCount(ctx)*num) + dch := make(chan *payload.Object_Distance, cap(res.GetResults())/2) + eg, ectx := errgroup.New(ctx) + var cancel context.CancelFunc + var timeout time.Duration + if to := cfg.GetTimeout(); to != 0 { + timeout = time.Duration(to) + } else { + timeout = s.timeout + } + ectx, cancel = context.WithTimeout(ectx, timeout) + + eg.Go(safety.RecoverFunc(func() error { + defer cancel() + // cl := new(checkList) + visited := make(map[string]bool, len(res.Results)) + mu := sync.RWMutex{} + return s.gateway.BroadCast(ectx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + r, err := f(ctx, ac, copts...) + if err != nil { + log.Debug(err) + return nil + } + for _, dist := range r.GetResults() { + if dist.GetDistance() > math.Float32frombits(atomic.LoadUint32(&maxDist)) { + return nil + } + id := dist.GetId() + mu.RLock() + if !visited[id] { + mu.RUnlock() + mu.Lock() + visited[id] = true + mu.Unlock() + dch <- dist + } else { + mu.RUnlock() + } + // if !cl.Exists(id) { + // dch <- dist + // cl.Check(id) + // } + } + return nil + }) + })) + for { + select { + case <-ectx.Done(): + err = eg.Wait() + if err != nil { + log.Error(err) + } + close(dch) + if len(res.GetResults()) > num && num != 0 { + res.Results = res.Results[:num] + } + uuids := make([]string, 0, len(res.Results)) + for _, r := range res.Results { + uuids = append(uuids, r.GetId()) + } + if s.metadata != nil { + metas, merr := s.metadata.GetMetas(ctx, uuids...) + if merr != nil { + log.Error(merr) + err = errors.Wrap(err, merr.Error()) + } + for i, k := range metas { + if len(k) != 0 { + res.Results[i].Id = k + } + } + } + if s.filter != nil { + r, ferr := s.filter.FilterSearch(ctx, res) + if ferr == nil { + res = r + } else { + err = errors.Wrap(err, ferr.Error()) + } + } + if err != nil { + return res, status.WrapWithInternal(fmt.Sprintf("failed to search request %#v", cfg), err, info.Get()) + } + return res, nil + case dist := <-dch: + if len(res.GetResults()) >= num && + dist.GetDistance() < math.Float32frombits(atomic.LoadUint32(&maxDist)) { + atomic.StoreUint32(&maxDist, math.Float32bits(dist.GetDistance())) + } + switch len(res.GetResults()) { + case 0: + res.Results = append(res.Results, dist) + continue + case 1: + if res.GetResults()[0].GetDistance() <= dist.GetDistance() { + res.Results = append(res.Results, dist) + } else { + res.Results = append([]*payload.Object_Distance{dist}, res.Results[0]) + } + continue + } + + pos := len(res.GetResults()) + for idx := pos; idx >= 1; idx-- { + if res.GetResults()[idx-1].GetDistance() <= dist.GetDistance() { + pos = idx - 1 + break + } + } + switch { + case pos == len(res.GetResults()): + res.Results = append([]*payload.Object_Distance{dist}, res.Results...) + case pos == len(res.GetResults())-1: + res.Results = append(res.GetResults(), dist) + case pos >= 0: + res.Results = append(res.GetResults()[:pos+1], res.GetResults()[pos:]...) + res.Results[pos+1] = dist + } + if len(res.GetResults()) > num && num != 0 { + res.Results = res.GetResults()[:num] + } + } + } +} + +func (s *server) StreamSearch(stream vald.Vald_StreamSearchServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamSearch") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Search_Request) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Search(ctx, data.(*payload.Search_Request)) + }) +} + +func (s *server) StreamSearchByID(stream vald.Vald_StreamSearchByIDServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamSearchByID") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Search_IDRequest) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.SearchByID(ctx, data.(*payload.Search_IDRequest)) + }) +} + +func (s *server) Insert(ctx context.Context, vec *payload.Object_Vector) (ce *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Insert") + defer func() { + if span != nil { + span.End() + } + }() + meta := vec.GetId() + exists, err := s.metadata.Exists(ctx, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal( + fmt.Sprintf("Insert API meta %s couldn't check meta already exists or not", meta), err, info.Get()) + } + if exists { + err = errors.Wrap(err, errors.ErrMetaDataAlreadyExists(meta).Error()) + if span != nil { + span.SetStatus(trace.StatusCodeAlreadyExists(err.Error())) + } + return nil, status.WrapWithAlreadyExists(fmt.Sprintf("Insert API meta %s already exists", meta), err, info.Get()) + } + + uuid := fuid.String() + err = s.metadata.SetUUIDandMeta(ctx, uuid, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Insert API meta %s & uuid %s couldn't store", meta, uuid), err, info.Get()) + } + vec.Id = uuid + mu := new(sync.Mutex) + targets := make([]string, 0, s.replica) + err = s.gateway.DoMulti(ctx, s.replica, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) (err error) { + _, err = ac.Insert(ctx, vec, copts...) + if err != nil { + if err == errors.ErrRPCCallFailed(target, context.Canceled) { + return nil + } + return err + } + target = strings.SplitN(target, ":", 2)[0] + mu.Lock() + targets = append(targets, target) + mu.Unlock() + return nil + }) + if err != nil { + err = errors.Wrapf(err, "Insert API (do multiple) failed to Insert uuid = %s\tmeta = %s\t info = %#v", uuid, meta, info.Get()) + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Insert API failed to Execute DoMulti error = %s", err.Error()), err, info.Get()) + } + if s.backup != nil { + vecs := &payload.Backup_MetaVector{ + Uuid: uuid, + Meta: meta, + Ips: targets, + } + if vec != nil { + vecs.Vector = vec.GetVector() + } + err = s.backup.Register(ctx, vecs) + if err != nil { + err = errors.Wrapf(err, "Insert API (backup.Register) failed to Backup Vectors = %#v\t info = %#v", vecs, info.Get()) + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(err.Error(), err) + } + } + log.Debugf("Insert API insert succeeded to %v", targets) + return new(payload.Empty), nil +} + +func (s *server) StreamInsert(stream vald.Vald_StreamInsertServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamInsert") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Insert(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiInsert(ctx context.Context, vecs *payload.Object_Vectors) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiInsert") + defer func() { + if span != nil { + span.End() + } + }() + metaMap := make(map[string]string) + metas := make([]string, 0, len(vecs.GetVectors())) + for i, vec := range vecs.GetVectors() { + uuid := fuid.String() + meta := vec.GetId() + metaMap[uuid] = meta + metas = append(metas, meta) + vecs.Vectors[i].Id = uuid + } + + for _, meta := range metas { + exists, err := s.metadata.Exists(ctx, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal( + fmt.Sprintf("MultiInsert API couldn't check metadata exists or not metas = %v", metas), err, info.Get()) + } + if exists { + if span != nil { + span.SetStatus(trace.StatusCodeAlreadyExists(err.Error())) + } + return nil, status.WrapWithAlreadyExists( + fmt.Sprintf("MultiInsert API failed metadata already exists meta = %s", meta), err, info.Get()) + } + } + + err = s.metadata.SetUUIDandMetas(ctx, metaMap) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed SetUUIDandMetas %#v", metaMap), err, info.Get()) + } + + mu := new(sync.Mutex) + targets := make([]string, 0, s.replica) + gerr := s.gateway.DoMulti(ctx, s.replica, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) (err error) { + _, err = ac.MultiInsert(ctx, vecs, copts...) + if err != nil { + return err + } + target = strings.SplitN(target, ":", 2)[0] + mu.Lock() + targets = append(targets, target) + mu.Unlock() + return nil + }) + if gerr != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed request %#v", vecs), errors.Wrap(gerr, err.Error()), info.Get()) + } + + if s.backup != nil { + mvecs := new(payload.Backup_MetaVectors) + mvecs.Vectors = make([]*payload.Backup_MetaVector, 0, len(vecs.GetVectors())) + for _, vec := range vecs.GetVectors() { + uuid := vec.GetId() + mvecs.Vectors = append(mvecs.Vectors, &payload.Backup_MetaVector{ + Uuid: uuid, + Meta: metaMap[uuid], + Vector: vec.GetVector(), + Ips: targets, + }) + } + err = s.backup.RegisterMultiple(ctx, mvecs) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed RegisterMultiple %#v", mvecs), err, info.Get()) + } + } + return new(payload.Empty), nil +} + +func (s *server) Update(ctx context.Context, vec *payload.Object_Vector) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Update") + defer func() { + if span != nil { + span.End() + } + }() + meta := vec.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Update API failed GetUUID meta = %s", meta), err, info.Get()) + } + vec.Id = uuid + locs, err := s.backup.GetLocation(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Update API failed GetLocation meta = %s, uuid = %s", meta, uuid), err, info.Get()) + } + lmap := make(map[string]struct{}, len(locs)) + for _, loc := range locs { + lmap[loc] = struct{}{} + } + err = s.gateway.BroadCast(ctx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + target = strings.SplitN(target, ":", 2)[0] + _, ok := lmap[target] + if ok { + _, err = ac.Update(ctx, vec, copts...) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Update API failed request %#v", vec), err, info.Get()) + } + mvec := &payload.Backup_MetaVector{ + Uuid: uuid, + Meta: meta, + Vector: vec.GetVector(), + Ips: locs, + } + err = s.backup.Register(ctx, mvec) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Update API failed backup %#v", vec), err, info.Get()) + } + + return new(payload.Empty), nil +} + +func (s *server) StreamUpdate(stream vald.Vald_StreamUpdateServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamUpdate") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Update(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiUpdate(ctx context.Context, vecs *payload.Object_Vectors) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiUpdate") + defer func() { + if span != nil { + span.End() + } + }() + ids := make([]string, 0, len(vecs.GetVectors())) + for _, vec := range vecs.GetVectors() { + ids = append(ids, vec.GetId()) + } + _, err = s.MultiRemove(ctx, &payload.Object_IDs{ + Ids: ids, + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiUpdate API failed Remove request %#v", ids), err, info.Get()) + } + _, err = s.MultiInsert(ctx, vecs) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiUpdate API failed Insert request %#v", vecs), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) Upsert(ctx context.Context, vec *payload.Object_Vector) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Upsert") + defer func() { + if span != nil { + span.End() + } + }() + + meta := vec.GetId() + exists, errs := s.metadata.Exists(ctx, meta) + if errs != nil { + log.Error(errs) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(errs.Error())) + } + } + + if exists { + _, err := s.Update(ctx, vec) + if err != nil { + errs = errors.Wrap(errs, err.Error()) + } + } else { + _, err := s.Insert(ctx, vec) + if err != nil { + errs = errors.Wrap(errs, err.Error()) + } + } + + return new(payload.Empty), errs +} + +func (s *server) StreamUpsert(stream vald.Vald_StreamUpsertServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamUpsert") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Upsert(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiUpsert(ctx context.Context, vecs *payload.Object_Vectors) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiUpsert") + defer func() { + if span != nil { + span.End() + } + }() + + insertVecs := make([]*payload.Object_Vector, 0, len(vecs.GetVectors())) + updateVecs := make([]*payload.Object_Vector, 0, len(vecs.GetVectors())) + + var errs error + for _, vec := range vecs.GetVectors() { + exists, err := s.metadata.Exists(ctx, vec.GetId()) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + errs = errors.Wrap(errs, err.Error()) + } + + if exists { + updateVecs = append(updateVecs, vec) + } else { + insertVecs = append(insertVecs, vec) + } + } + + eg, ectx := errgroup.New(ctx) + + eg.Go(safety.RecoverFunc(func() error { + var err error + if len(updateVecs) > 0 { + _, err = s.MultiUpdate(ectx, &payload.Object_Vectors{ + Vectors: updateVecs, + }) + } + return err + })) + + eg.Go(safety.RecoverFunc(func() error { + var err error + if len(insertVecs) > 0 { + _, err = s.MultiInsert(ectx, &payload.Object_Vectors{ + Vectors: insertVecs, + }) + } + return err + })) + + err := eg.Wait() + if err != nil { + errs = errors.Wrap(errs, err.Error()) + return nil, status.WrapWithInternal("MultiUpsert API failed", errs, info.Get()) + } + + return new(payload.Empty), errs +} + +func (s *server) Remove(ctx context.Context, id *payload.Object_ID) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.Remove") + defer func() { + if span != nil { + span.End() + } + }() + meta := id.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Remove API meta %s's uuid not found", meta), err, info.Get()) + } + locs, err := s.backup.GetLocation(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Remove API failed GetLocation meta = %s, uuid = %s", meta, uuid), err, info.Get()) + } + lmap := make(map[string]struct{}, len(locs)) + for _, loc := range locs { + lmap[loc] = struct{}{} + } + err = s.gateway.BroadCast(ctx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + _, ok := lmap[target] + if ok { + _, err = ac.Remove(ctx, &payload.Object_ID{ + Id: uuid, + }, copts...) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed request uuid %s", uuid), err, info.Get()) + } + _, err = s.metadata.DeleteMeta(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed Delete metadata uuid = %s", uuid), err, info.Get()) + } + err = s.backup.Remove(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed to Remove backup uuid = %s", uuid), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) StreamRemove(stream vald.Vald_StreamRemoveServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamRemove") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_ID) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Remove(ctx, data.(*payload.Object_ID)) + }) +} + +func (s *server) MultiRemove(ctx context.Context, ids *payload.Object_IDs) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.MultiRemove") + defer func() { + if span != nil { + span.End() + } + }() + uuids, err := s.metadata.GetUUIDs(ctx, ids.GetIds()...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("MultiRemove API meta datas %v's uuid not found", ids.GetIds()), err, info.Get()) + } + lmap := make(map[string][]string, s.gateway.GetAgentCount(ctx)) + for _, uuid := range uuids { + locs, err := s.backup.GetLocation(ctx, uuid) + if err != nil { + return nil, status.WrapWithNotFound(fmt.Sprintf("MultiRemove API failed to get uuid %s's location ", uuid), err, info.Get()) + } + for _, loc := range locs { + lmap[loc] = append(lmap[loc], uuid) + } + } + err = s.gateway.BroadCast(ctx, func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error { + uuids, ok := lmap[target] + if ok { + _, err := ac.MultiRemove(ctx, &payload.Object_IDs{ + Ids: uuids, + }, copts...) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to request uuids %v metas %v ", uuids, ids.GetIds()), err, info.Get()) + } + _, err = s.metadata.DeleteMetas(ctx, uuids...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to DeleteMetas uuids %v ", uuids), err, info.Get()) + } + err = s.backup.RemoveMultiple(ctx, uuids...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to Remove backup uuids %v ", uuids), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) GetObject(ctx context.Context, id *payload.Object_ID) (vec *payload.Backup_MetaVector, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald.GetObject") + defer func() { + if span != nil { + span.End() + } + }() + meta := id.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("GetObject API meta %s's uuid not found", meta), err, info.Get()) + } + vec, err = s.backup.GetObject(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("GetObject API meta %s uuid %s Object not found", meta, uuid), err, info.Get()) + } + return vec, nil +} + +func (s *server) StreamGetObject(stream vald.Vald_StreamGetObjectServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-vald.StreamGetObject") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_ID) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.GetObject(ctx, data.(*payload.Object_ID)) + }) +} diff --git a/pkg/gateway/lb/handler/grpc/handler_test.go b/pkg/gateway/lb/handler/grpc/handler_test.go new file mode 100644 index 00000000000..84311c9e1e2 --- /dev/null +++ b/pkg/gateway/lb/handler/grpc/handler_test.go @@ -0,0 +1,2440 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "context" + "reflect" + "testing" + "time" + + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/pkg/gateway/lb/service" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want vald.ValdServer + } + type test struct { + name string + args args + want want + checkFunc func(want, vald.ValdServer) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got vald.ValdServer) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Exists(t *testing.T) { + type args struct { + ctx context.Context + meta *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Object_ID + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Object_ID, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Object_ID, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Exists(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Search(t *testing.T) { + type args struct { + ctx context.Context + req *payload.Search_Request + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.Search(test.args.ctx, test.args.req) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_SearchByID(t *testing.T) { + type args struct { + ctx context.Context + req *payload.Search_IDRequest + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.SearchByID(test.args.ctx, test.args.req) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_search(t *testing.T) { + type args struct { + ctx context.Context + cfg *payload.Search_Config + f func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + cfg: nil, + f: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + cfg: nil, + f: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.search(test.args.ctx, test.args.cfg, test.args.f) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamSearch(t *testing.T) { + type args struct { + stream vald.Vald_StreamSearchServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamSearch(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamSearchByID(t *testing.T) { + type args struct { + stream vald.Vald_StreamSearchByIDServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamSearchByID(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Insert(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantCe *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCe *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCe, w.wantCe) { + return errors.Errorf("got = %v, want %v", gotCe, w.wantCe) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotCe, err := s.Insert(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, gotCe, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamInsert(t *testing.T) { + type args struct { + stream vald.Vald_StreamInsertServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamInsert(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiInsert(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiInsert(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Update(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.Update(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamUpdate(t *testing.T) { + type args struct { + stream vald.Vald_StreamUpdateServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamUpdate(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiUpdate(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiUpdate(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Upsert(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Upsert(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamUpsert(t *testing.T) { + type args struct { + stream vald.Vald_StreamUpsertServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamUpsert(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiUpsert(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.MultiUpsert(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Remove(t *testing.T) { + type args struct { + ctx context.Context + id *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Remove(test.args.ctx, test.args.id) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamRemove(t *testing.T) { + type args struct { + stream vald.Vald_StreamRemoveServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamRemove(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiRemove(t *testing.T) { + type args struct { + ctx context.Context + ids *payload.Object_IDs + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + ids: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + ids: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiRemove(test.args.ctx, test.args.ids) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_GetObject(t *testing.T) { + type args struct { + ctx context.Context + id *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantVec *payload.Backup_MetaVector + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Backup_MetaVector, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotVec *payload.Backup_MetaVector, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotVec, w.wantVec) { + return errors.Errorf("got = %v, want %v", gotVec, w.wantVec) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotVec, err := s.GetObject(test.args.ctx, test.args.id) + if err := test.checkFunc(test.want, gotVec, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamGetObject(t *testing.T) { + type args struct { + stream vald.Vald_StreamGetObjectServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamGetObject(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/handler/grpc/option.go b/pkg/gateway/lb/handler/grpc/option.go new file mode 100644 index 00000000000..876b902f1fd --- /dev/null +++ b/pkg/gateway/lb/handler/grpc/option.go @@ -0,0 +1,103 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "time" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/timeutil" + "github.com/vdaas/vald/pkg/gateway/lb/service" +) + +type Option func(*server) + +var ( + defaultOpts = []Option{ + WithErrGroup(errgroup.Get()), + WithReplicationCount(3), + WithStreamConcurrency(20), + WithTimeout("5s"), + } +) + +func WithGateway(g service.Gateway) Option { + return func(s *server) { + if g != nil { + s.gateway = g + } + } +} + +func WithMeta(m service.Meta) Option { + return func(s *server) { + if m != nil { + s.metadata = m + } + } +} + +func WithBackup(b service.Backup) Option { + return func(s *server) { + if b != nil { + s.backup = b + } + } +} + +func WithFilters(filter service.Filter) Option { + return func(s *server) { + if filter != nil { + s.filter = filter + } + } +} + +func WithErrGroup(eg errgroup.Group) Option { + return func(s *server) { + if eg != nil { + s.eg = eg + } + } +} + +func WithTimeout(dur string) Option { + return func(s *server) { + d, err := timeutil.Parse(dur) + if err != nil { + d = time.Second * 10 + } + s.timeout = d + } +} + +func WithReplicationCount(rep int) Option { + return func(s *server) { + if rep > 1 { + s.replica = rep + } + } +} + +func WithStreamConcurrency(c int) Option { + return func(s *server) { + if c != 0 { + s.streamConcurrency = c + } + } +} diff --git a/pkg/gateway/lb/handler/grpc/option_test.go b/pkg/gateway/lb/handler/grpc/option_test.go new file mode 100644 index 00000000000..b2b127bdc07 --- /dev/null +++ b/pkg/gateway/lb/handler/grpc/option_test.go @@ -0,0 +1,931 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "testing" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/pkg/gateway/lb/service" + + "go.uber.org/goleak" +) + +func TestWithGateway(t *testing.T) { + type T = interface{} + type args struct { + g service.Gateway + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + g: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + g: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithGateway(test.args.g) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithGateway(test.args.g) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMeta(t *testing.T) { + type T = interface{} + type args struct { + m service.Meta + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + m: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + m: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMeta(test.args.m) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMeta(test.args.m) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithBackup(t *testing.T) { + type T = interface{} + type args struct { + b service.Backup + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + b: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + b: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackup(test.args.b) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackup(test.args.b) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithFilters(t *testing.T) { + type T = interface{} + type args struct { + filter service.Filter + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + filter: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + filter: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithFilters(test.args.filter) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithFilters(test.args.filter) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithErrGroup(t *testing.T) { + type T = interface{} + type args struct { + eg errgroup.Group + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithErrGroup(test.args.eg) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithErrGroup(test.args.eg) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithTimeout(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithTimeout(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithTimeout(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithReplicationCount(t *testing.T) { + type T = interface{} + type args struct { + rep int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + rep: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + rep: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithReplicationCount(test.args.rep) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithReplicationCount(test.args.rep) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithStreamConcurrency(t *testing.T) { + type T = interface{} + type args struct { + c int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + c: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + c: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithStreamConcurrency(test.args.c) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithStreamConcurrency(test.args.c) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/lb/handler/rest/handler.go b/pkg/gateway/lb/handler/rest/handler.go new file mode 100644 index 00000000000..c9b9b962660 --- /dev/null +++ b/pkg/gateway/lb/handler/rest/handler.go @@ -0,0 +1,131 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "net/http" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/net/http/dump" + "github.com/vdaas/vald/internal/net/http/json" +) + +type Handler interface { + Index(w http.ResponseWriter, r *http.Request) (int, error) + Exists(w http.ResponseWriter, r *http.Request) (int, error) + Search(w http.ResponseWriter, r *http.Request) (int, error) + SearchByID(w http.ResponseWriter, r *http.Request) (int, error) + Insert(w http.ResponseWriter, r *http.Request) (int, error) + MultiInsert(w http.ResponseWriter, r *http.Request) (int, error) + Update(w http.ResponseWriter, r *http.Request) (int, error) + MultiUpdate(w http.ResponseWriter, r *http.Request) (int, error) + Remove(w http.ResponseWriter, r *http.Request) (int, error) + MultiRemove(w http.ResponseWriter, r *http.Request) (int, error) + GetObject(w http.ResponseWriter, r *http.Request) (int, error) +} + +type handler struct { + vald vald.ValdServer +} + +func New(opts ...Option) Handler { + h := new(handler) + + for _, opt := range append(defaultOpts, opts...) { + opt(h) + } + return h +} + +func (h *handler) Index(w http.ResponseWriter, r *http.Request) (int, error) { + data := make(map[string]interface{}) + return json.Handler(w, r, &data, func() (interface{}, error) { + return dump.Request(nil, data, r) + }) +} + +func (h *handler) Search(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Search_Request + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Search(r.Context(), req) + }) +} + +func (h *handler) SearchByID(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Search_IDRequest + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.SearchByID(r.Context(), req) + }) +} + +func (h *handler) Insert(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vector + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Insert(r.Context(), req) + }) +} + +func (h *handler) MultiInsert(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vectors + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiInsert(r.Context(), req) + }) +} + +func (h *handler) Update(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vector + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Update(r.Context(), req) + }) +} + +func (h *handler) MultiUpdate(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vectors + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiUpdate(r.Context(), req) + }) +} + +func (h *handler) Remove(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Remove(r.Context(), req) + }) +} + +func (h *handler) MultiRemove(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_IDs + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiRemove(r.Context(), req) + }) +} + +func (h *handler) GetObject(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.GetObject(r.Context(), req) + }) +} + +func (h *handler) Exists(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Exists(r.Context(), req) + }) +} diff --git a/pkg/gateway/lb/handler/rest/handler_test.go b/pkg/gateway/lb/handler/rest/handler_test.go new file mode 100644 index 00000000000..37fee9c24f7 --- /dev/null +++ b/pkg/gateway/lb/handler/rest/handler_test.go @@ -0,0 +1,1101 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "net/http" + "reflect" + "testing" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/internal/errors" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want Handler + } + type test struct { + name string + args args + want want + checkFunc func(want, Handler) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got Handler) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Index(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + want int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + got, err := h.Index(test.args.w, test.args.r) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Search(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Search(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_SearchByID(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.SearchByID(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Insert(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Insert(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiInsert(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiInsert(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Update(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Update(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiUpdate(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiUpdate(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Remove(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Remove(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiRemove(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiRemove(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_GetObject(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.GetObject(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Exists(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Exists(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/handler/rest/option.go b/pkg/gateway/lb/handler/rest/option.go new file mode 100644 index 00000000000..c684ad7ec83 --- /dev/null +++ b/pkg/gateway/lb/handler/rest/option.go @@ -0,0 +1,32 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import "github.com/vdaas/vald/apis/grpc/gateway/vald" + +type Option func(*handler) + +var ( + defaultOpts = []Option{} +) + +func WithVald(v vald.ValdServer) Option { + return func(h *handler) { + h.vald = v + } +} diff --git a/pkg/gateway/lb/handler/rest/option_test.go b/pkg/gateway/lb/handler/rest/option_test.go new file mode 100644 index 00000000000..3f900a77c5c --- /dev/null +++ b/pkg/gateway/lb/handler/rest/option_test.go @@ -0,0 +1,139 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "testing" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + + "go.uber.org/goleak" +) + +func TestWithVald(t *testing.T) { + type T = interface{} + type args struct { + v vald.ValdServer + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + v: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + v: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithVald(test.args.v) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithVald(test.args.v) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/lb/router/option.go b/pkg/gateway/lb/router/option.go new file mode 100644 index 00000000000..34f6c3b145c --- /dev/null +++ b/pkg/gateway/lb/router/option.go @@ -0,0 +1,42 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "github.com/vdaas/vald/pkg/gateway/lb/handler/rest" +) + +type Option func(*router) + +var ( + defaultOpts = []Option{ + WithTimeout("3s"), + } +) + +func WithHandler(h rest.Handler) Option { + return func(r *router) { + r.handler = h + } +} + +func WithTimeout(timeout string) Option { + return func(r *router) { + r.timeout = timeout + } +} diff --git a/pkg/gateway/lb/router/option_test.go b/pkg/gateway/lb/router/option_test.go new file mode 100644 index 00000000000..22b74577c2d --- /dev/null +++ b/pkg/gateway/lb/router/option_test.go @@ -0,0 +1,252 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "testing" + + "github.com/vdaas/vald/pkg/gateway/lb/handler/rest" + + "go.uber.org/goleak" +) + +func TestWithHandler(t *testing.T) { + type T = interface{} + type args struct { + h rest.Handler + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + h: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + h: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithHandler(test.args.h) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithHandler(test.args.h) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithTimeout(t *testing.T) { + type T = interface{} + type args struct { + timeout string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + timeout: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + timeout: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithTimeout(test.args.timeout) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithTimeout(test.args.timeout) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/lb/router/router.go b/pkg/gateway/lb/router/router.go new file mode 100644 index 00000000000..7991af7bfd0 --- /dev/null +++ b/pkg/gateway/lb/router/router.go @@ -0,0 +1,130 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "net/http" + + "github.com/vdaas/vald/internal/net/http/routing" + "github.com/vdaas/vald/pkg/gateway/lb/handler/rest" +) + +type router struct { + handler rest.Handler + timeout string +} + +// New returns REST route&method information from handler interface +func New(opts ...Option) http.Handler { + r := new(router) + + for _, opt := range append(defaultOpts, opts...) { + opt(r) + } + + h := r.handler + + return routing.New( + routing.WithRoutes([]routing.Route{ + { + "Index", + []string{ + http.MethodGet, + }, + "/", + h.Index, + }, + { + "Search", + []string{ + http.MethodPost, + }, + "/search", + h.Search, + }, + { + "Search By ID", + []string{ + http.MethodGet, + }, + "/search/{id}", + h.SearchByID, + }, + { + "Insert", + []string{ + http.MethodPost, + }, + "/insert", + h.Insert, + }, + { + "Multiple Insert", + []string{ + http.MethodPost, + }, + "/insert/multi", + h.MultiInsert, + }, + { + "Update", + []string{ + http.MethodPost, + http.MethodPatch, + http.MethodPut, + }, + "/update", + h.Update, + }, + { + "Multiple Update", + []string{ + http.MethodPost, + http.MethodPatch, + http.MethodPut, + }, + "/update/multi", + h.MultiUpdate, + }, + { + "Remove", + []string{ + http.MethodDelete, + }, + "/delete/{id}", + h.Remove, + }, + { + "Multiple Remove", + []string{ + http.MethodDelete, + http.MethodPost, + }, + "/delete/multi", + h.MultiRemove, + }, + { + "GetObject", + []string{ + http.MethodGet, + }, + "/object/{id}", + h.GetObject, + }, + }...)) +} diff --git a/pkg/gateway/lb/router/router_test.go b/pkg/gateway/lb/router/router_test.go new file mode 100644 index 00000000000..876b9574c48 --- /dev/null +++ b/pkg/gateway/lb/router/router_test.go @@ -0,0 +1,96 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "net/http" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errors" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want http.Handler + } + type test struct { + name string + args args + want want + checkFunc func(want, http.Handler) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got http.Handler) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/service/backup.go b/pkg/gateway/lb/service/backup.go new file mode 100644 index 00000000000..bc50e649047 --- /dev/null +++ b/pkg/gateway/lb/service/backup.go @@ -0,0 +1,138 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + + "github.com/vdaas/vald/apis/grpc/manager/compressor" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" +) + +type Backup interface { + Start(ctx context.Context) (<-chan error, error) + GetObject(ctx context.Context, uuid string) (*payload.Backup_MetaVector, error) + GetLocation(ctx context.Context, uuid string) ([]string, error) + Register(ctx context.Context, vec *payload.Backup_MetaVector) error + RegisterMultiple(ctx context.Context, vecs *payload.Backup_MetaVectors) error + Remove(ctx context.Context, uuid string) error + RemoveMultiple(ctx context.Context, uuids ...string) error +} + +type backup struct { + addr string + client grpc.Client +} + +func NewBackup(opts ...BackupOption) (bu Backup, err error) { + b := new(backup) + for _, opt := range append(defaultBackupOpts, opts...) { + if err := opt(b); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + + return b, nil +} + +func (b *backup) Start(ctx context.Context) (<-chan error, error) { + return b.client.StartConnectionMonitor(ctx) +} + +func (b *backup) GetObject(ctx context.Context, uuid string) (vec *payload.Backup_MetaVector, err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + vec, err = compressor.NewBackupClient(conn).GetVector(ctx, &payload.Backup_GetVector_Request{ + Uuid: uuid, + }, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) GetLocation(ctx context.Context, uuid string) (ipList []string, err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + ips, err := compressor.NewBackupClient(conn).Locations(ctx, &payload.Backup_Locations_Request{ + Uuid: uuid, + }, copts...) + if err != nil { + return nil, err + } + ipList = ips.GetIp() + return + }) + return +} + +func (b *backup) Register(ctx context.Context, vec *payload.Backup_MetaVector) (err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).Register(ctx, vec, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) RegisterMultiple(ctx context.Context, vecs *payload.Backup_MetaVectors) (err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).RegisterMulti(ctx, vecs, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) Remove(ctx context.Context, uuid string) (err error) { + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).Remove(ctx, &payload.Backup_Remove_Request{ + Uuid: uuid, + }, copts...) + if err != nil { + return nil, err + } + return + }) + return +} + +func (b *backup) RemoveMultiple(ctx context.Context, uuids ...string) (err error) { + req := new(payload.Backup_Remove_RequestMulti) + req.Uuids = uuids + _, err = b.client.Do(ctx, b.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (i interface{}, err error) { + _, err = compressor.NewBackupClient(conn).RemoveMulti(ctx, req, copts...) + if err != nil { + return nil, err + } + return + }) + return +} diff --git a/pkg/gateway/lb/service/backup_option.go b/pkg/gateway/lb/service/backup_option.go new file mode 100644 index 00000000000..3647333b074 --- /dev/null +++ b/pkg/gateway/lb/service/backup_option.go @@ -0,0 +1,42 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import "github.com/vdaas/vald/internal/net/grpc" + +type BackupOption func(b *backup) error + +var ( + defaultBackupOpts = []BackupOption{} +) + +func WithBackupAddr(addr string) BackupOption { + return func(b *backup) error { + b.addr = addr + return nil + } +} + +func WithBackupClient(client grpc.Client) BackupOption { + return func(b *backup) error { + if client != nil { + b.client = client + } + return nil + } +} diff --git a/pkg/gateway/lb/service/backup_option_test.go b/pkg/gateway/lb/service/backup_option_test.go new file mode 100644 index 00000000000..ca7bca08cf7 --- /dev/null +++ b/pkg/gateway/lb/service/backup_option_test.go @@ -0,0 +1,252 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestWithBackupAddr(t *testing.T) { + type T = interface{} + type args struct { + addr string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackupAddr(test.args.addr) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackupAddr(test.args.addr) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithBackupClient(t *testing.T) { + type T = interface{} + type args struct { + client grpc.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackupClient(test.args.client) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackupClient(test.args.client) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/lb/service/backup_test.go b/pkg/gateway/lb/service/backup_test.go new file mode 100644 index 00000000000..2d6c262f692 --- /dev/null +++ b/pkg/gateway/lb/service/backup_test.go @@ -0,0 +1,750 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewBackup(t *testing.T) { + type args struct { + opts []BackupOption + } + type want struct { + wantBu Backup + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Backup, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotBu Backup, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotBu, w.wantBu) { + return errors.Errorf("got = %v, want %v", gotBu, w.wantBu) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotBu, err := NewBackup(test.args.opts...) + if err := test.checkFunc(test.want, gotBu, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + got, err := b.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_GetObject(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + wantVec *payload.Backup_MetaVector + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Backup_MetaVector, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotVec *payload.Backup_MetaVector, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotVec, w.wantVec) { + return errors.Errorf("got = %v, want %v", gotVec, w.wantVec) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + gotVec, err := b.GetObject(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotVec, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_GetLocation(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + wantIpList []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotIpList []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotIpList, w.wantIpList) { + return errors.Errorf("got = %v, want %v", gotIpList, w.wantIpList) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + gotIpList, err := b.GetLocation(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotIpList, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_Register(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Backup_MetaVector + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.Register(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_RegisterMultiple(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Backup_MetaVectors + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.RegisterMultiple(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_Remove(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.Remove(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_backup_RemoveMultiple(t *testing.T) { + type args struct { + ctx context.Context + uuids []string + } + type fields struct { + addr string + client grpc.Client + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + b := &backup{ + addr: test.fields.addr, + client: test.fields.client, + } + + err := b.RemoveMultiple(test.args.ctx, test.args.uuids...) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/service/doc.go b/pkg/gateway/lb/service/doc.go new file mode 100644 index 00000000000..c13956cbbe3 --- /dev/null +++ b/pkg/gateway/lb/service/doc.go @@ -0,0 +1,18 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service manages the main logic of server. +package service diff --git a/pkg/gateway/lb/service/filter.go b/pkg/gateway/lb/service/filter.go new file mode 100644 index 00000000000..819ee59431a --- /dev/null +++ b/pkg/gateway/lb/service/filter.go @@ -0,0 +1,67 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + + "github.com/vdaas/vald/apis/grpc/filter/egress" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" +) + +type Filter interface { + Start(ctx context.Context) (<-chan error, error) + FilterSearch(context.Context, *payload.Search_Response) (*payload.Search_Response, error) +} + +type filter struct { + client grpc.Client +} + +func NewFilter(opts ...FilterOption) (ef Filter, err error) { + f := new(filter) + for _, opt := range append(defaultFilterOpts, opts...) { + if err := opt(f); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + + return f, nil +} + +func (f *filter) Start(ctx context.Context) (<-chan error, error) { + return f.client.StartConnectionMonitor(ctx) +} + +func (f *filter) FilterSearch(ctx context.Context, res *payload.Search_Response) (*payload.Search_Response, error) { + var rerr error + f.client.Range(ctx, + func(ctx context.Context, addr string, conn *grpc.ClientConn, copts ...grpc.CallOption) error { + r, err := egress.NewEgressFilterClient(conn).Filter(ctx, res, copts...) + if err != nil { + rerr = errors.Wrap(rerr, err.Error()) + } else { + res = r + } + return nil + }) + + return res, rerr +} diff --git a/pkg/gateway/lb/service/filter_option.go b/pkg/gateway/lb/service/filter_option.go new file mode 100644 index 00000000000..de11d286d22 --- /dev/null +++ b/pkg/gateway/lb/service/filter_option.go @@ -0,0 +1,35 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import "github.com/vdaas/vald/internal/net/grpc" + +type FilterOption func(f *filter) error + +var ( + defaultFilterOpts = []FilterOption{} +) + +func WithFilterClient(client grpc.Client) FilterOption { + return func(f *filter) error { + if client != nil { + f.client = client + } + return nil + } +} diff --git a/pkg/gateway/lb/service/filter_option_test.go b/pkg/gateway/lb/service/filter_option_test.go new file mode 100644 index 00000000000..80e30f9c0d3 --- /dev/null +++ b/pkg/gateway/lb/service/filter_option_test.go @@ -0,0 +1,139 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestWithFilterClient(t *testing.T) { + type T = interface{} + type args struct { + client grpc.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithFilterClient(test.args.client) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithFilterClient(test.args.client) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/lb/service/filter_test.go b/pkg/gateway/lb/service/filter_test.go new file mode 100644 index 00000000000..e03f77c8214 --- /dev/null +++ b/pkg/gateway/lb/service/filter_test.go @@ -0,0 +1,283 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package service + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewFilter(t *testing.T) { + type args struct { + opts []FilterOption + } + type want struct { + wantEf Filter + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Filter, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotEf Filter, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotEf, w.wantEf) { + return errors.Errorf("got = %v, want %v", gotEf, w.wantEf) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotEf, err := NewFilter(test.args.opts...) + if err := test.checkFunc(test.want, gotEf, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_filter_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + client grpc.Client + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + f := &filter{ + client: test.fields.client, + } + + got, err := f.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_filter_FilterSearch(t *testing.T) { + type args struct { + ctx context.Context + res *payload.Search_Response + } + type fields struct { + client grpc.Client + } + type want struct { + want *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + res: nil, + }, + fields: fields { + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + res: nil, + }, + fields: fields { + client: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + f := &filter{ + client: test.fields.client, + } + + got, err := f.FilterSearch(test.args.ctx, test.args.res) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/service/gateway.go b/pkg/gateway/lb/service/gateway.go new file mode 100644 index 00000000000..06469551ad2 --- /dev/null +++ b/pkg/gateway/lb/service/gateway.go @@ -0,0 +1,119 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "context" + "reflect" + "sync/atomic" + + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/internal/client/discoverer" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/net/grpc" +) + +type Gateway interface { + Start(ctx context.Context) (<-chan error, error) + GetAgentCount(ctx context.Context) int + Do(ctx context.Context, + f func(ctx context.Context, tgt string, ac agent.AgentClient, copts ...grpc.CallOption) error) error + DoMulti(ctx context.Context, num int, + f func(ctx context.Context, tgt string, ac agent.AgentClient, copts ...grpc.CallOption) error) error + BroadCast(ctx context.Context, + f func(ctx context.Context, tgt string, ac agent.AgentClient, copts ...grpc.CallOption) error) error +} + +type gateway struct { + client discoverer.Client + eg errgroup.Group +} + +func NewGateway(opts ...GWOption) (gw Gateway, err error) { + g := new(gateway) + for _, opt := range append(defaultGWOpts, opts...) { + if err := opt(g); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + return g, nil +} + +func (g *gateway) Start(ctx context.Context) (<-chan error, error) { + return g.client.Start(ctx) +} + +func (g *gateway) BroadCast(ctx context.Context, + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error) (err error) { + return g.client.GetClient().RangeConcurrent(ctx, -1, func(ctx context.Context, + addr string, conn *grpc.ClientConn, copts ...grpc.CallOption) (err error) { + select { + case <-ctx.Done(): + return nil + default: + err = f(ctx, addr, agent.NewAgentClient(conn), copts...) + if err != nil { + log.Debug(addr, err) + return err + } + } + return nil + }) +} + +func (g *gateway) Do(ctx context.Context, + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error) (err error) { + addr := g.client.GetAddrs(ctx)[0] + _, err = g.client.GetClient().Do(ctx, addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + return nil, f(ctx, addr, agent.NewAgentClient(conn), copts...) + }) + return err +} + +func (g *gateway) DoMulti(ctx context.Context, num int, + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error) (err error) { + var cur uint32 = 0 + limit := uint32(num) + addrs := g.client.GetAddrs(ctx) + log.Debug("DoMulti", addrs) + err = g.client.GetClient().OrderedRange(ctx, addrs, func(ictx context.Context, + addr string, + conn *grpc.ClientConn, + copts ...grpc.CallOption) (err error) { + if atomic.LoadUint32(&cur) < limit { + err = f(ictx, addr, agent.NewAgentClient(conn), copts...) + if err != nil { + log.Debug(addr, err) + return err + } + atomic.AddUint32(&cur, 1) + } + return nil + }) + if err != nil && cur < limit { + return err + } + return nil +} + +func (g *gateway) GetAgentCount(ctx context.Context) int { + return len(g.client.GetAddrs(ctx)) +} diff --git a/pkg/gateway/lb/service/gateway_option.go b/pkg/gateway/lb/service/gateway_option.go new file mode 100644 index 00000000000..b385031d804 --- /dev/null +++ b/pkg/gateway/lb/service/gateway_option.go @@ -0,0 +1,49 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "github.com/vdaas/vald/internal/client/discoverer" + "github.com/vdaas/vald/internal/errgroup" +) + +type GWOption func(g *gateway) error + +var ( + defaultGWOpts = []GWOption{ + WithErrGroup(errgroup.Get()), + } +) + +func WithDiscoverer(c discoverer.Client) GWOption { + return func(g *gateway) error { + if c != nil { + g.client = c + } + return nil + } +} + +func WithErrGroup(eg errgroup.Group) GWOption { + return func(g *gateway) error { + if eg != nil { + g.eg = eg + } + return nil + } +} diff --git a/pkg/gateway/lb/service/gateway_option_test.go b/pkg/gateway/lb/service/gateway_option_test.go new file mode 100644 index 00000000000..7a4c8cea021 --- /dev/null +++ b/pkg/gateway/lb/service/gateway_option_test.go @@ -0,0 +1,253 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/client/discoverer" + "github.com/vdaas/vald/internal/errgroup" + + "go.uber.org/goleak" +) + +func TestWithDiscoverer(t *testing.T) { + type T = interface{} + type args struct { + c discoverer.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithDiscoverer(test.args.c) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithDiscoverer(test.args.c) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithErrGroup(t *testing.T) { + type T = interface{} + type args struct { + eg errgroup.Group + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithErrGroup(test.args.eg) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithErrGroup(test.args.eg) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/lb/service/gateway_test.go b/pkg/gateway/lb/service/gateway_test.go new file mode 100644 index 00000000000..b2592a62b00 --- /dev/null +++ b/pkg/gateway/lb/service/gateway_test.go @@ -0,0 +1,563 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "context" + "reflect" + "testing" + + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/internal/client/discoverer" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewGateway(t *testing.T) { + type args struct { + opts []GWOption + } + type want struct { + wantGw Gateway + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Gateway, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotGw Gateway, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotGw, w.wantGw) { + return errors.Errorf("got = %v, want %v", gotGw, w.wantGw) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotGw, err := NewGateway(test.args.opts...) + if err := test.checkFunc(test.want, gotGw, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + got, err := g.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_BroadCast(t *testing.T) { + type args struct { + ctx context.Context + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + err := g.BroadCast(test.args.ctx, test.args.f) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_Do(t *testing.T) { + type args struct { + ctx context.Context + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + err := g.Do(test.args.ctx, test.args.f) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_DoMulti(t *testing.T) { + type args struct { + ctx context.Context + num int + f func(ctx context.Context, target string, ac agent.AgentClient, copts ...grpc.CallOption) error + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + num: 0, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + num: 0, + f: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + err := g.DoMulti(test.args.ctx, test.args.num, test.args.f) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_gateway_GetAgentCount(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + client discoverer.Client + eg errgroup.Group + } + type want struct { + want int + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got int) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + client: nil, + eg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + g := &gateway{ + client: test.fields.client, + eg: test.fields.eg, + } + + got := g.GetAgentCount(test.args.ctx) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/service/meta.go b/pkg/gateway/lb/service/meta.go new file mode 100644 index 00000000000..1ca8f43ffb6 --- /dev/null +++ b/pkg/gateway/lb/service/meta.go @@ -0,0 +1,490 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service provides meta service +package service + +import ( + "context" + "reflect" + + gmeta "github.com/vdaas/vald/apis/grpc/meta" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/status" + "github.com/vdaas/vald/internal/observability/trace" +) + +type Meta interface { + Start(ctx context.Context) (<-chan error, error) + Exists(context.Context, string) (bool, error) + GetMeta(context.Context, string) (string, error) + GetMetas(context.Context, ...string) ([]string, error) + GetUUID(context.Context, string) (string, error) + GetUUIDs(context.Context, ...string) ([]string, error) + SetUUIDandMeta(context.Context, string, string) error + SetUUIDandMetas(context.Context, map[string]string) error + DeleteMeta(context.Context, string) (string, error) + DeleteMetas(context.Context, ...string) ([]string, error) + DeleteUUID(context.Context, string) (string, error) + DeleteUUIDs(context.Context, ...string) ([]string, error) +} + +type meta struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string +} + +const ( + uuidCacheKeyPref = "uuid-" + metaCacheKeyPref = "meta-" +) + +func NewMeta(opts ...MetaOption) (mi Meta, err error) { + m := new(meta) + for _, opt := range append(defaultMetaOpts, opts...) { + if err = opt(m); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + if m.enableCache { + if m.cache == nil { + m.cache, err = cache.New( + cache.WithExpireDuration(m.expireDuration), + cache.WithExpireCheckDuration(m.expireCheckDuration), + ) + if err != nil { + return nil, err + } + } + } + + return m, nil +} + +func (m *meta) Start(ctx context.Context) (<-chan error, error) { + if m.enableCache && m.cache != nil { + m.cache.Start(ctx) + } + return m.client.StartConnectionMonitor(ctx) +} + +func (m *meta) Exists(ctx context.Context, meta string) (bool, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.Exists") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + _, ok := m.cache.Get(uuidCacheKeyPref + meta) + if ok { + return true, nil + } + } + key, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + key, err := gmeta.NewMetaClient(conn).GetMetaInverse(ctx, &payload.Meta_Val{ + Val: meta, + }, copts...) + if err != nil { + if status.Code(err) == status.NotFound { + return "", nil + } + return nil, err + } + return key.GetKey(), nil + }) + if err != nil { + return false, err + } + + k := key.(string) + if k == "" { + return false, nil + } + + if m.enableCache { + m.cache.Set(uuidCacheKeyPref+meta, k) + m.cache.Set(metaCacheKeyPref+k, meta) + } + return true, nil +} + +func (m *meta) GetMeta(ctx context.Context, uuid string) (v string, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetMeta") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + data, ok := m.cache.Get(metaCacheKeyPref + uuid) + if ok { + return data.(string), nil + } + } + val, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + val, err := gmeta.NewMetaClient(conn).GetMeta(ctx, &payload.Meta_Key{ + Key: uuid, + }, copts...) + if err != nil { + return nil, err + } + return val.GetVal(), nil + }) + if err != nil { + return "", err + } + v = val.(string) + + if m.enableCache { + m.cache.Set(metaCacheKeyPref+uuid, v) + m.cache.Set(uuidCacheKeyPref+v, uuid) + } + return v, nil +} + +func (m *meta) GetMetas(ctx context.Context, uuids ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetMetas") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + metas, ok := func() (metas []string, ok bool) { + for _, uuid := range uuids { + data, ok := m.cache.Get(metaCacheKeyPref + uuid) + if !ok { + return nil, false + } + metas = append(metas, data.(string)) + } + return metas, true + }() + if ok { + return metas, nil + } + } + vals, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + vals, err := gmeta.NewMetaClient(conn).GetMetas(ctx, &payload.Meta_Keys{ + Keys: uuids, + }, copts...) + if vals != nil { + return vals.GetVals(), err + } + return nil, err + }) + if vals != nil { + vs, ok := vals.([]string) + if ok { + if m.enableCache { + for i, v := range vs { + uuid := uuids[i] + m.cache.Set(metaCacheKeyPref+uuid, v) + m.cache.Set(uuidCacheKeyPref+v, uuid) + } + } + return vs, err + } + } + return nil, err +} + +func (m *meta) GetUUID(ctx context.Context, meta string) (k string, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetUUID") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + data, ok := m.cache.Get(uuidCacheKeyPref + meta) + if ok { + return data.(string), nil + } + } + key, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + key, err := gmeta.NewMetaClient(conn).GetMetaInverse(ctx, &payload.Meta_Val{ + Val: meta, + }, copts...) + if err != nil { + return nil, err + } + return key.GetKey(), nil + }) + if err != nil { + return "", err + } + + k = key.(string) + if m.enableCache { + m.cache.Set(uuidCacheKeyPref+meta, k) + m.cache.Set(metaCacheKeyPref+k, meta) + } + return k, nil +} + +func (m *meta) GetUUIDs(ctx context.Context, metas ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetUUIDs") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + uuids, ok := func() (uuids []string, ok bool) { + for _, meta := range metas { + data, ok := m.cache.Get(uuidCacheKeyPref + meta) + if !ok { + return nil, false + } + uuids = append(uuids, data.(string)) + } + return uuids, true + }() + if ok { + return uuids, nil + } + } + keys, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + keys, err := gmeta.NewMetaClient(conn).GetMetasInverse(ctx, &payload.Meta_Vals{ + Vals: metas, + }, copts...) + if keys != nil { + return keys.GetKeys(), err + } + return nil, err + }) + if keys != nil { + ks, ok := keys.([]string) + if ok { + if m.enableCache { + for i, k := range ks { + meta := metas[i] + m.cache.Set(uuidCacheKeyPref+meta, k) + m.cache.Set(metaCacheKeyPref+k, meta) + } + } + return ks, err + } + } + return nil, err +} + +func (m *meta) SetUUIDandMeta(ctx context.Context, uuid, meta string) (err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.SetUUIDandMeta") + defer func() { + if span != nil { + span.End() + } + }() + + _, err = m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + _, err := gmeta.NewMetaClient(conn).SetMeta(ctx, &payload.Meta_KeyVal{ + Key: uuid, + Val: meta, + }, copts...) + + return nil, err + }) + if err != nil { + return err + } + + if m.enableCache { + m.cache.Set(uuidCacheKeyPref+meta, uuid) + m.cache.Set(metaCacheKeyPref+uuid, meta) + } + return nil +} + +func (m *meta) SetUUIDandMetas(ctx context.Context, kvs map[string]string) (err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.SetUUIDandMetas") + defer func() { + if span != nil { + span.End() + } + }() + + data := make([]*payload.Meta_KeyVal, 0, len(kvs)) + for uuid, meta := range kvs { + data = append(data, &payload.Meta_KeyVal{ + Key: uuid, + Val: meta, + }) + } + _, err = m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + _, err := gmeta.NewMetaClient(conn).SetMetas(ctx, &payload.Meta_KeyVals{ + Kvs: data, + }, copts...) + + return nil, err + }) + if err != nil { + return err + } + + if m.enableCache { + for uuid, meta := range kvs { + m.cache.Set(uuidCacheKeyPref+meta, uuid) + m.cache.Set(metaCacheKeyPref+uuid, meta) + } + } + return nil +} + +func (m *meta) DeleteMeta(ctx context.Context, uuid string) (v string, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteMeta") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + meta, ok := m.cache.GetAndDelete(metaCacheKeyPref + uuid) + if ok { + m.cache.Delete(uuidCacheKeyPref + meta.(string)) + } + } + val, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + val, err := gmeta.NewMetaClient(conn).DeleteMeta(ctx, &payload.Meta_Key{ + Key: uuid, + }, copts...) + if err != nil { + return nil, err + } + return val.GetVal(), nil + }) + if err != nil { + return "", err + } + return val.(string), nil +} + +func (m *meta) DeleteMetas(ctx context.Context, uuids ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteMetas") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + for _, uuid := range uuids { + meta, ok := m.cache.GetAndDelete(metaCacheKeyPref + uuid) + if ok { + m.cache.Delete(uuidCacheKeyPref + meta.(string)) + } + } + } + vals, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + vals, err := gmeta.NewMetaClient(conn).DeleteMetas(ctx, &payload.Meta_Keys{ + Keys: uuids, + }, copts...) + if err != nil { + return nil, err + } + return vals.GetVals(), nil + }) + if err != nil { + return nil, err + } + return vals.([]string), nil +} + +func (m *meta) DeleteUUID(ctx context.Context, meta string) (string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteUUID") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + uuid, ok := m.cache.GetAndDelete(uuidCacheKeyPref + meta) + if ok { + m.cache.Delete(metaCacheKeyPref + uuid.(string)) + } + } + key, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + key, err := gmeta.NewMetaClient(conn).DeleteMetaInverse(ctx, &payload.Meta_Val{ + Val: meta, + }, copts...) + if err != nil { + return nil, err + } + return key.GetKey(), nil + }) + if err != nil { + return "", err + } + return key.(string), nil +} + +func (m *meta) DeleteUUIDs(ctx context.Context, metas ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteUUIDs") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + for _, meta := range metas { + uuid, ok := m.cache.GetAndDelete(uuidCacheKeyPref + meta) + if ok { + m.cache.Delete(metaCacheKeyPref + uuid.(string)) + } + } + } + keys, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + keys, err := gmeta.NewMetaClient(conn).DeleteMetasInverse(ctx, &payload.Meta_Vals{ + Vals: metas, + }, copts...) + if err != nil { + return nil, err + } + return keys.GetKeys(), nil + }) + if err != nil { + return nil, err + } + return keys.([]string), nil +} diff --git a/pkg/gateway/lb/service/meta_option.go b/pkg/gateway/lb/service/meta_option.go new file mode 100644 index 00000000000..a5014a18687 --- /dev/null +++ b/pkg/gateway/lb/service/meta_option.go @@ -0,0 +1,97 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "fmt" + + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/timeutil" +) + +type MetaOption func(m *meta) error + +var ( + defaultMetaOpts = []MetaOption{ + WithMetaCacheEnabled(true), + WithMetaCacheExpireDuration("30m"), + WithMetaCacheExpiredCheckDuration("2m"), + } +) + +func WithMetaAddr(addr string) MetaOption { + return func(m *meta) error { + m.addr = addr + return nil + } +} + +func WithMetaHostPort(host string, port int) MetaOption { + return func(m *meta) error { + m.addr = fmt.Sprintf("%s:%d", host, port) + return nil + } +} + +func WithMetaClient(client grpc.Client) MetaOption { + return func(m *meta) error { + if client != nil { + m.client = client + } + return nil + } +} + +func WithMetaCacheEnabled(flg bool) MetaOption { + return func(m *meta) error { + m.enableCache = flg + return nil + } +} + +func WithMetaCache(c cache.Cache) MetaOption { + return func(m *meta) error { + if c != nil { + m.cache = c + } + return nil + } +} + +func WithMetaCacheExpireDuration(dur string) MetaOption { + return func(m *meta) error { + _, err := timeutil.Parse(dur) + if err != nil { + return err + } + m.expireDuration = dur + return nil + } +} + +func WithMetaCacheExpiredCheckDuration(dur string) MetaOption { + return func(m *meta) error { + _, err := timeutil.Parse(dur) + if err != nil { + return err + } + m.expireCheckDuration = dur + return nil + } +} diff --git a/pkg/gateway/lb/service/meta_option_test.go b/pkg/gateway/lb/service/meta_option_test.go new file mode 100644 index 00000000000..4aa31369999 --- /dev/null +++ b/pkg/gateway/lb/service/meta_option_test.go @@ -0,0 +1,821 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestWithMetaAddr(t *testing.T) { + type T = interface{} + type args struct { + addr string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaAddr(test.args.addr) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaAddr(test.args.addr) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaHostPort(t *testing.T) { + type T = interface{} + type args struct { + host string + port int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + host: "", + port: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + host: "", + port: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaHostPort(test.args.host, test.args.port) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaHostPort(test.args.host, test.args.port) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaClient(t *testing.T) { + type T = interface{} + type args struct { + client grpc.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaClient(test.args.client) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaClient(test.args.client) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCacheEnabled(t *testing.T) { + type T = interface{} + type args struct { + flg bool + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + flg: false, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + flg: false, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCacheEnabled(test.args.flg) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCacheEnabled(test.args.flg) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCache(t *testing.T) { + type T = interface{} + type args struct { + c cache.Cache + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCache(test.args.c) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCache(test.args.c) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCacheExpireDuration(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCacheExpireDuration(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCacheExpireDuration(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCacheExpiredCheckDuration(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCacheExpiredCheckDuration(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCacheExpiredCheckDuration(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/lb/service/meta_test.go b/pkg/gateway/lb/service/meta_test.go new file mode 100644 index 00000000000..c2d0835a8ac --- /dev/null +++ b/pkg/gateway/lb/service/meta_test.go @@ -0,0 +1,1429 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service provides meta service +package service + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewMeta(t *testing.T) { + type args struct { + opts []MetaOption + } + type want struct { + wantMi Meta + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Meta, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotMi Meta, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotMi, w.wantMi) { + return errors.Errorf("got = %v, want %v", gotMi, w.wantMi) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotMi, err := NewMeta(test.args.opts...) + if err := test.checkFunc(test.want, gotMi, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_Exists(t *testing.T) { + type args struct { + ctx context.Context + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want bool + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, bool, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got bool, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.Exists(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetMeta(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + wantV string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotV string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotV, w.wantV) { + return errors.Errorf("got = %v, want %v", gotV, w.wantV) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + gotV, err := m.GetMeta(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotV, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetMetas(t *testing.T) { + type args struct { + ctx context.Context + uuids []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.GetMetas(test.args.ctx, test.args.uuids...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetUUID(t *testing.T) { + type args struct { + ctx context.Context + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + wantK string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotK string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotK, w.wantK) { + return errors.Errorf("got = %v, want %v", gotK, w.wantK) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + gotK, err := m.GetUUID(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, gotK, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetUUIDs(t *testing.T) { + type args struct { + ctx context.Context + metas []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.GetUUIDs(test.args.ctx, test.args.metas...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_SetUUIDandMeta(t *testing.T) { + type args struct { + ctx context.Context + uuid string + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + err := m.SetUUIDandMeta(test.args.ctx, test.args.uuid, test.args.meta) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_SetUUIDandMetas(t *testing.T) { + type args struct { + ctx context.Context + kvs map[string]string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + kvs: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + kvs: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + err := m.SetUUIDandMetas(test.args.ctx, test.args.kvs) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteMeta(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + wantV string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotV string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotV, w.wantV) { + return errors.Errorf("got = %v, want %v", gotV, w.wantV) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + gotV, err := m.DeleteMeta(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotV, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteMetas(t *testing.T) { + type args struct { + ctx context.Context + uuids []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.DeleteMetas(test.args.ctx, test.args.uuids...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteUUID(t *testing.T) { + type args struct { + ctx context.Context + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.DeleteUUID(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteUUIDs(t *testing.T) { + type args struct { + ctx context.Context + metas []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.DeleteUUIDs(test.args.ctx, test.args.metas...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/lb/usecase/vald.go b/pkg/gateway/lb/usecase/vald.go new file mode 100644 index 00000000000..cdb11fc2adc --- /dev/null +++ b/pkg/gateway/lb/usecase/vald.go @@ -0,0 +1,328 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package usecase + +import ( + "context" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/internal/client/discoverer" + iconf "github.com/vdaas/vald/internal/config" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/metric" + "github.com/vdaas/vald/internal/observability" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/internal/servers/server" + "github.com/vdaas/vald/internal/servers/starter" + "github.com/vdaas/vald/pkg/gateway/lb/config" + handler "github.com/vdaas/vald/pkg/gateway/lb/handler/grpc" + "github.com/vdaas/vald/pkg/gateway/lb/handler/rest" + "github.com/vdaas/vald/pkg/gateway/lb/router" + "github.com/vdaas/vald/pkg/gateway/lb/service" +) + +type run struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup +} + +func New(cfg *config.Data) (r runner.Runner, err error) { + eg := errgroup.Get() + + var ( + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + ) + + if addrs := cfg.Gateway.BackupManager.Client.Addrs; len(addrs) == 0 { + return nil, errors.ErrInvalidBackupConfig + } + + backupClientOptions := append( + cfg.Gateway.BackupManager.Client.Opts(), + grpc.WithErrGroup(eg), + ) + + discovererClientOptions := append( + cfg.Gateway.Discoverer.Client.Opts(), + grpc.WithErrGroup(eg), + ) + + metadataClientOptions := append( + cfg.Gateway.Meta.Client.Opts(), + grpc.WithErrGroup(eg), + ) + + var obs observability.Observability + if cfg.Observability.Enabled { + obs, err = observability.NewWithConfig(cfg.Observability) + if err != nil { + return nil, err + } + backupClientOptions = append( + backupClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + discovererClientOptions = append( + discovererClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + metadataClientOptions = append( + metadataClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + } + + backup, err = service.NewBackup( + service.WithBackupAddr(cfg.Gateway.BackupManager.Client.Addrs[0]), + service.WithBackupClient( + grpc.New(backupClientOptions...), + ), + ) + if err != nil { + return nil, err + } + client, err := discoverer.New( + discoverer.WithAutoConnect(true), + discoverer.WithName(cfg.Gateway.AgentName), + discoverer.WithNamespace(cfg.Gateway.AgentNamespace), + discoverer.WithPort(cfg.Gateway.AgentPort), + discoverer.WithServiceDNSARecord(cfg.Gateway.AgentDNS), + discoverer.WithDiscovererClient(grpc.New(discovererClientOptions...)), + discoverer.WithDiscovererHostPort( + cfg.Gateway.Discoverer.Host, + cfg.Gateway.Discoverer.Port, + ), + discoverer.WithDiscoverDuration(cfg.Gateway.Discoverer.Duration), + discoverer.WithOptions(cfg.Gateway.Discoverer.AgentClient.Opts()...), + discoverer.WithNodeName(cfg.Gateway.NodeName), + ) + if err != nil { + return nil, err + } + gateway, err = service.NewGateway( + service.WithErrGroup(eg), + service.WithDiscoverer(client), + ) + if err != nil { + return nil, err + } + + if addrs := cfg.Gateway.Meta.Client.Addrs; len(addrs) == 0 { + return nil, errors.ErrInvalidMetaDataConfig + } + metadata, err = service.NewMeta( + service.WithMetaAddr(cfg.Gateway.Meta.Client.Addrs[0]), + service.WithMetaClient( + grpc.New(metadataClientOptions...), + ), + service.WithMetaCacheEnabled(cfg.Gateway.Meta.EnableCache), + service.WithMetaCacheExpireDuration(cfg.Gateway.Meta.CacheExpiration), + service.WithMetaCacheExpiredCheckDuration(cfg.Gateway.Meta.ExpiredCacheCheckDuration), + ) + if err != nil { + return nil, err + } + + ef := cfg.Gateway.EgressFilter + if ef != nil && + ef.Client != nil && + ef.Client.Addrs != nil && + len(ef.Client.Addrs) != 0 { + egressFilterClientOptions := append( + ef.Client.Opts(), + grpc.WithErrGroup(eg), + ) + if cfg.Observability.Enabled { + egressFilterClientOptions = append( + egressFilterClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + } + filter, err = service.NewFilter( + service.WithFilterClient( + grpc.New(egressFilterClientOptions...), + ), + ) + } + + v := handler.New( + handler.WithGateway(gateway), + handler.WithBackup(backup), + handler.WithMeta(metadata), + handler.WithFilters(filter), + handler.WithErrGroup(eg), + handler.WithReplicationCount(cfg.Gateway.IndexReplica), + handler.WithStreamConcurrency(cfg.Server.GetGRPCStreamConcurrency()), + ) + + grpcServerOptions := []server.Option{ + server.WithGRPCRegistFunc(func(srv *grpc.Server) { + vald.RegisterValdServer(srv, v) + }), + server.WithPreStopFunction(func() error { + // TODO notify another gateway and scheduler + return nil + }), + } + + if cfg.Observability.Enabled { + grpcServerOptions = append( + grpcServerOptions, + server.WithGRPCOption( + grpc.StatsHandler(metric.NewServerHandler()), + ), + ) + } + + srv, err := starter.New( + starter.WithConfig(cfg.Server), + starter.WithREST(func(sc *iconf.Server) []server.Option { + return []server.Option{ + server.WithHTTPHandler( + router.New( + router.WithHandler( + rest.New( + rest.WithVald(v), + ), + ), + ), + ), + } + }), + starter.WithGRPC(func(sc *iconf.Server) []server.Option { + return grpcServerOptions + }), + // TODO add GraphQL handler + ) + if err != nil { + return nil, err + } + + return &run{ + eg: eg, + cfg: cfg, + server: srv, + observability: obs, + filter: filter, + gateway: gateway, + metadata: metadata, + backup: backup, + }, nil +} + +func (r *run) PreStart(ctx context.Context) error { + if r.observability != nil { + return r.observability.PreStart(ctx) + } + return nil +} + +func (r *run) Start(ctx context.Context) (<-chan error, error) { + ech := make(chan error, 6) + var bech, fech, mech, gech, sech, oech <-chan error + var err error + if r.observability != nil { + oech = r.observability.Start(ctx) + } + if r.backup != nil { + bech, err = r.backup.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + if r.filter != nil { + fech, err = r.filter.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + if r.metadata != nil { + mech, err = r.metadata.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + if r.gateway != nil { + gech, err = r.gateway.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + sech = r.server.ListenAndServe(ctx) + r.eg.Go(safety.RecoverFunc(func() (err error) { + defer close(ech) + for { + select { + case <-ctx.Done(): + return ctx.Err() + case err = <-oech: + case err = <-bech: + case err = <-fech: + case err = <-gech: + case err = <-mech: + case err = <-sech: + } + if err != nil { + select { + case <-ctx.Done(): + return ctx.Err() + case ech <- err: + } + } + } + })) + return ech, nil +} + +func (r *run) PreStop(ctx context.Context) error { + return nil +} + +func (r *run) Stop(ctx context.Context) error { + if r.observability != nil { + r.observability.Stop(ctx) + } + return r.server.Shutdown(ctx) +} + +func (r *run) PostStop(ctx context.Context) error { + return nil +} diff --git a/pkg/gateway/lb/usecase/vald_test.go b/pkg/gateway/lb/usecase/vald_test.go new file mode 100644 index 00000000000..fce9f93a1de --- /dev/null +++ b/pkg/gateway/lb/usecase/vald_test.go @@ -0,0 +1,672 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package usecase + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/observability" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/servers/starter" + "github.com/vdaas/vald/pkg/gateway/lb/config" + "github.com/vdaas/vald/pkg/gateway/lb/service" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + cfg *config.Data + } + type want struct { + wantR runner.Runner + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, runner.Runner, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotR runner.Runner, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotR, w.wantR) { + return errors.Errorf("got = %v, want %v", gotR, w.wantR) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + cfg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + cfg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotR, err := New(test.args.cfg) + if err := test.checkFunc(test.want, gotR, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PreStart(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PreStart(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + got, err := r.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PreStop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PreStop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_Stop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.Stop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PostStop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PostStop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/meta/README.md b/pkg/gateway/meta/README.md new file mode 100644 index 00000000000..9b8d2e1af5c --- /dev/null +++ b/pkg/gateway/meta/README.md @@ -0,0 +1 @@ +# server sample diff --git a/pkg/gateway/meta/config/config.go b/pkg/gateway/meta/config/config.go new file mode 100644 index 00000000000..2fc4441f5ed --- /dev/null +++ b/pkg/gateway/meta/config/config.go @@ -0,0 +1,149 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package setting stores all server application settings +package config + +import ( + "github.com/vdaas/vald/internal/config" +) + +type GlobalConfig = config.GlobalConfig +type Server = config.Server + +// Config represent a application setting data content (config.yaml). +// In K8s environment, this configuration is stored in K8s ConfigMap. +type Data struct { + config.GlobalConfig `json:",inline" yaml:",inline"` + + // Server represent all server configurations + Server *config.Servers `json:"server_config" yaml:"server_config"` + + // Observability represent observability configurations + Observability *config.Observability `json:"observability" yaml:"observability"` + + // Gateway represent agent gateway service configuration + Meta *config.Meta `json:"meta" yaml:"meta"` +} + +func NewConfig(path string) (cfg *Data, err error) { + err = config.Read(path, &cfg) + + if err != nil { + return nil, err + } + + if cfg != nil { + cfg.Bind() + } + + if cfg.Server != nil { + cfg.Server = cfg.Server.Bind() + } + + if cfg.Observability != nil { + cfg.Observability = cfg.Observability.Bind() + } + + if cfg.Meta != nil { + cfg.Meta = cfg.Meta.Bind() + } + + return cfg, nil +} + +// func FakeData() { +// d := Data{ +// Version: "v0.0.1", +// Server: &config.Servers{ +// Servers: []*config.Server{ +// { +// Name: "agent-rest", +// Host: "127.0.0.1", +// Port: 8080, +// Mode: "REST", +// ProbeWaitTime: "3s", +// ShutdownDuration: "5s", +// HandlerTimeout: "5s", +// IdleTimeout: "2s", +// ReadHeaderTimeout: "1s", +// ReadTimeout: "1s", +// WriteTimeout: "1s", +// }, +// { +// Name: "agent-grpc", +// Host: "127.0.0.1", +// Port: 8082, +// Mode: "GRPC", +// }, +// }, +// MetricsServers: []*config.Server{ +// { +// Name: "pprof", +// Host: "127.0.0.1", +// Port: 6060, +// Mode: "REST", +// ProbeWaitTime: "3s", +// ShutdownDuration: "5s", +// HandlerTimeout: "5s", +// IdleTimeout: "2s", +// ReadHeaderTimeout: "1s", +// ReadTimeout: "1s", +// WriteTimeout: "1s", +// }, +// }, +// HealthCheckServers: []*config.Server{ +// { +// Name: "livenesss", +// Host: "127.0.0.1", +// Port: 3000, +// }, +// { +// Name: "readiness", +// Host: "127.0.0.1", +// Port: 3001, +// }, +// }, +// StartUpStrategy: []string{ +// "livenesss", +// "pprof", +// "agent-grpc", +// "agent-rest", +// "readiness", +// }, +// ShutdownStrategy: []string{ +// "readiness", +// "agent-rest", +// "agent-grpc", +// "pprof", +// "livenesss", +// }, +// FullShutdownDuration: "30s", +// TLS: &config.TLS{ +// Enabled: false, +// Cert: "/path/to/cert", +// Key: "/path/to/key", +// CA: "/path/to/ca", +// }, +// }, +// Gateway: &config.Gateway{ +// AgentPort: 8080, +// AgentName: "vald-agent", +// BackoffEnabled: false,, +// }, +// } +// fmt.Println(config.ToRawYaml(d)) +// } diff --git a/pkg/gateway/meta/config/config_test.go b/pkg/gateway/meta/config/config_test.go new file mode 100644 index 00000000000..e8090717ead --- /dev/null +++ b/pkg/gateway/meta/config/config_test.go @@ -0,0 +1,101 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package setting stores all server application settings +package config + +import ( + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errors" + "go.uber.org/goleak" +) + +func TestNewConfig(t *testing.T) { + type args struct { + path string + } + type want struct { + wantCfg *Data + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, *Data, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCfg *Data, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCfg, w.wantCfg) { + return errors.Errorf("got = %v, want %v", gotCfg, w.wantCfg) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + path: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + path: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotCfg, err := NewConfig(test.args.path) + if err := test.checkFunc(test.want, gotCfg, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/meta/handler/doc.go b/pkg/gateway/meta/handler/doc.go new file mode 100644 index 00000000000..86b6d1869df --- /dev/null +++ b/pkg/gateway/meta/handler/doc.go @@ -0,0 +1,17 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package handler diff --git a/pkg/gateway/meta/handler/grpc/handler.go b/pkg/gateway/meta/handler/grpc/handler.go new file mode 100644 index 00000000000..d0d15ef0245 --- /dev/null +++ b/pkg/gateway/meta/handler/grpc/handler.go @@ -0,0 +1,582 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "context" + "fmt" + "time" + + "github.com/kpango/fuid" + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + client "github.com/vdaas/vald/internal/client/gateway/vald" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/info" + "github.com/vdaas/vald/internal/log" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/status" + "github.com/vdaas/vald/internal/observability/trace" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/pkg/gateway/meta/service" +) + +type server struct { + eg errgroup.Group + metadata service.Meta + gateway client.Client + copts []grpc.CallOption + timeout time.Duration + replica int + streamConcurrency int +} + +func New(opts ...Option) vald.ValdServer { + s := new(server) + + for _, opt := range append(defaultOpts, opts...) { + opt(s) + } + + return s +} + +func (s *server) Exists(ctx context.Context, meta *payload.Object_ID) (*payload.Object_ID, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.Exists") + defer func() { + if span != nil { + span.End() + } + }() + uuid, err := s.metadata.GetUUID(ctx, meta.GetId()) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Exists API meta %s's uuid not found", meta.GetId()), err, meta.GetId(), info.Get()) + } + return &payload.Object_ID{ + Id: uuid, + }, nil +} + +func (s *server) Search(ctx context.Context, req *payload.Search_Request) (res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.Search") + defer func() { + if span != nil { + span.End() + } + }() + return s.search(ctx, func(ctx context.Context, vc vald.ValdClient, copts ...grpc.CallOption) (*payload.Search_Response, error) { + return vc.Search(ctx, req, copts...) + }) +} + +func (s *server) SearchByID(ctx context.Context, req *payload.Search_IDRequest) ( + res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.SearchByID") + defer func() { + if span != nil { + span.End() + } + }() + metaID := req.GetId() + req.Id, err = s.metadata.GetUUID(ctx, metaID) + if err != nil { + req.Id = metaID + log.Errorf("error at SearchByID\t%v", err) + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("SearchByID API meta %s's uuid not found", metaID), err, req, info.Get()) + } + return s.search(ctx, func(ctx context.Context, vc vald.ValdClient, copts ...grpc.CallOption) (*payload.Search_Response, error) { + return vc.SearchByID(ctx, req, copts...) + }) +} + +func (s *server) search(ctx context.Context, + f func(ctx context.Context, vc vald.ValdClient, copts ...grpc.CallOption) (*payload.Search_Response, error)) ( + res *payload.Search_Response, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.search") + defer func() { + if span != nil { + span.End() + } + }() + res, err = f(ctx, s.gateway, s.copts...) + if err != nil { + return nil, err + } + uuids := make([]string, 0, len(res.Results)) + for _, r := range res.Results { + uuids = append(uuids, r.GetId()) + } + if s.metadata != nil { + var metas []string + metas, err = s.metadata.GetMetas(ctx, uuids...) + for i, k := range metas { + if len(k) != 0 { + res.Results[i].Id = k + } + } + } + return res, err +} + +func (s *server) StreamSearch(stream vald.Vald_StreamSearchServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-meta.StreamSearch") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Search_Request) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Search(ctx, data.(*payload.Search_Request)) + }) +} + +func (s *server) StreamSearchByID(stream vald.Vald_StreamSearchByIDServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-meta.StreamSearchByID") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Search_IDRequest) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.SearchByID(ctx, data.(*payload.Search_IDRequest)) + }) +} + +func (s *server) Insert(ctx context.Context, vec *payload.Object_Vector) (ce *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.Insert") + defer func() { + if span != nil { + span.End() + } + }() + meta := vec.GetId() + exists, err := s.metadata.Exists(ctx, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal( + fmt.Sprintf("Insert API meta %s couldn't check meta already exists or not", meta), err, info.Get()) + } + if exists { + err = errors.Wrap(err, errors.ErrMetaDataAlreadyExists(meta).Error()) + if span != nil { + span.SetStatus(trace.StatusCodeAlreadyExists(err.Error())) + } + return nil, status.WrapWithAlreadyExists(fmt.Sprintf("Insert API meta %s already exists", meta), err, info.Get()) + } + uuid := fuid.String() + vec.Id = uuid + _, err = s.gateway.Insert(ctx, vec, s.copts...) + if err != nil { + err = errors.Wrapf(err, "Insert API (do multiple) failed to Insert uuid = %s\tmeta = %s\t info = %#v", uuid, meta, info.Get()) + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Insert API failed to Execute DoMulti error = %s", err.Error()), err, info.Get()) + } + err = s.metadata.SetUUIDandMeta(ctx, uuid, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Insert API meta %s & uuid %s couldn't store", meta, uuid), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) StreamInsert(stream vald.Vald_StreamInsertServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-meta.StreamInsert") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Insert(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiInsert(ctx context.Context, vecs *payload.Object_Vectors) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.MultiInsert") + defer func() { + if span != nil { + span.End() + } + }() + metaMap := make(map[string]string) + metas := make([]string, 0, len(vecs.GetVectors())) + for i, vec := range vecs.GetVectors() { + uuid := fuid.String() + meta := vec.GetId() + metaMap[uuid] = meta + metas = append(metas, meta) + vecs.Vectors[i].Id = uuid + } + + for _, meta := range metas { + exists, err := s.metadata.Exists(ctx, meta) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal( + fmt.Sprintf("MultiInsert API couldn't check metadata exists or not metas = %v", metas), err, info.Get()) + } + if exists { + if span != nil { + span.SetStatus(trace.StatusCodeAlreadyExists(err.Error())) + } + return nil, status.WrapWithAlreadyExists( + fmt.Sprintf("MultiInsert API failed metadata already exists meta = %s", meta), err, info.Get()) + } + } + + res, err = s.gateway.MultiInsert(ctx, vecs, s.copts...) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal("got error from MultiInsert API", err, info.Get()) + } + + err = s.metadata.SetUUIDandMetas(ctx, metaMap) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiInsert API failed SetUUIDandMetas %#v", metaMap), err, info.Get()) + } + + return res, nil +} + +func (s *server) Update(ctx context.Context, vec *payload.Object_Vector) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.Update") + defer func() { + if span != nil { + span.End() + } + }() + meta := vec.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Update API failed GetUUID meta = %s", meta), err, info.Get()) + } + vec.Id = uuid + res, err = s.gateway.Update(ctx, vec, s.copts...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Update API failed request %#v", vec), err, info.Get()) + } + + return new(payload.Empty), nil +} + +func (s *server) StreamUpdate(stream vald.Vald_StreamUpdateServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-meta.StreamUpdate") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Update(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiUpdate(ctx context.Context, vecs *payload.Object_Vectors) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.MultiUpdate") + defer func() { + if span != nil { + span.End() + } + }() + ids := make([]string, 0, len(vecs.GetVectors())) + for _, vec := range vecs.GetVectors() { + ids = append(ids, vec.GetId()) + } + _, err = s.MultiRemove(ctx, &payload.Object_IDs{ + Ids: ids, + }) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiUpdate API failed Remove request %#v", ids), err, info.Get()) + } + _, err = s.MultiInsert(ctx, vecs) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiUpdate API failed Insert request %#v", vecs), err, info.Get()) + } + return new(payload.Empty), nil +} + +func (s *server) Upsert(ctx context.Context, vec *payload.Object_Vector) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.Upsert") + defer func() { + if span != nil { + span.End() + } + }() + + meta := vec.GetId() + exists, errs := s.metadata.Exists(ctx, meta) + if errs != nil { + log.Error(errs) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(errs.Error())) + } + } + + if exists { + _, err := s.Update(ctx, vec) + if err != nil { + errs = errors.Wrap(errs, err.Error()) + } + } else { + _, err := s.Insert(ctx, vec) + if err != nil { + errs = errors.Wrap(errs, err.Error()) + } + } + + return new(payload.Empty), errs +} + +func (s *server) StreamUpsert(stream vald.Vald_StreamUpsertServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-meta.StreamUpsert") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_Vector) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Upsert(ctx, data.(*payload.Object_Vector)) + }) +} + +func (s *server) MultiUpsert(ctx context.Context, vecs *payload.Object_Vectors) (*payload.Empty, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.MultiUpsert") + defer func() { + if span != nil { + span.End() + } + }() + + insertVecs := make([]*payload.Object_Vector, 0, len(vecs.GetVectors())) + updateVecs := make([]*payload.Object_Vector, 0, len(vecs.GetVectors())) + + var errs error + for _, vec := range vecs.GetVectors() { + exists, err := s.metadata.Exists(ctx, vec.GetId()) + if err != nil { + log.Error(err) + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + errs = errors.Wrap(errs, err.Error()) + } + + if exists { + updateVecs = append(updateVecs, vec) + } else { + insertVecs = append(insertVecs, vec) + } + } + + eg, ectx := errgroup.New(ctx) + + eg.Go(safety.RecoverFunc(func() error { + var err error + if len(updateVecs) > 0 { + _, err = s.MultiUpdate(ectx, &payload.Object_Vectors{ + Vectors: updateVecs, + }) + } + return err + })) + + eg.Go(safety.RecoverFunc(func() error { + var err error + if len(insertVecs) > 0 { + _, err = s.MultiInsert(ectx, &payload.Object_Vectors{ + Vectors: insertVecs, + }) + } + return err + })) + + err := eg.Wait() + if err != nil { + errs = errors.Wrap(errs, err.Error()) + return nil, status.WrapWithInternal("MultiUpsert API failed", errs, info.Get()) + } + + return new(payload.Empty), errs +} + +func (s *server) Remove(ctx context.Context, id *payload.Object_ID) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.Remove") + defer func() { + if span != nil { + span.End() + } + }() + meta := id.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("Remove API meta %s's uuid not found", meta), err, info.Get()) + } + + id.Id = uuid + res, err = s.gateway.Remove(ctx, id, s.copts...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed request uuid %s", uuid), err, info.Get()) + } + _, err = s.metadata.DeleteMeta(ctx, uuid) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("Remove API failed Delete metadata uuid = %s", uuid), err, info.Get()) + } + return res, nil +} + +func (s *server) StreamRemove(stream vald.Vald_StreamRemoveServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-meta.StreamRemove") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_ID) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.Remove(ctx, data.(*payload.Object_ID)) + }) +} + +func (s *server) MultiRemove(ctx context.Context, ids *payload.Object_IDs) (res *payload.Empty, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.MultiRemove") + defer func() { + if span != nil { + span.End() + } + }() + uuids, err := s.metadata.GetUUIDs(ctx, ids.GetIds()...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("MultiRemove API meta datas %v's uuid not found", ids.GetIds()), err, info.Get()) + } + ids.Ids = uuids + res, err = s.gateway.MultiRemove(ctx, ids, s.copts...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to request uuids %v metas %v ", uuids, ids.GetIds()), err, info.Get()) + } + _, err = s.metadata.DeleteMetas(ctx, uuids...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeInternal(err.Error())) + } + return nil, status.WrapWithInternal(fmt.Sprintf("MultiRemove API failed to DeleteMetas uuids %v ", uuids), err, info.Get()) + } + return res, nil +} + +func (s *server) GetObject(ctx context.Context, id *payload.Object_ID) (vec *payload.Backup_MetaVector, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-meta.GetObject") + defer func() { + if span != nil { + span.End() + } + }() + meta := id.GetId() + uuid, err := s.metadata.GetUUID(ctx, meta) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("GetObject API meta %s's uuid not found", meta), err, info.Get()) + } + id.Id = uuid + vec, err = s.gateway.GetObject(ctx, id, s.copts...) + if err != nil { + if span != nil { + span.SetStatus(trace.StatusCodeNotFound(err.Error())) + } + return nil, status.WrapWithNotFound(fmt.Sprintf("GetObject API meta %s uuid %s Object not found", meta, uuid), err, info.Get()) + } + return vec, nil +} + +func (s *server) StreamGetObject(stream vald.Vald_StreamGetObjectServer) error { + ctx, span := trace.StartSpan(stream.Context(), "vald/gateway-meta.StreamGetObject") + defer func() { + if span != nil { + span.End() + } + }() + return grpc.BidirectionalStream(ctx, stream, s.streamConcurrency, + func() interface{} { return new(payload.Object_ID) }, + func(ctx context.Context, data interface{}) (interface{}, error) { + return s.GetObject(ctx, data.(*payload.Object_ID)) + }) +} diff --git a/pkg/gateway/meta/handler/grpc/handler_test.go b/pkg/gateway/meta/handler/grpc/handler_test.go new file mode 100644 index 00000000000..9c1bce2dccd --- /dev/null +++ b/pkg/gateway/meta/handler/grpc/handler_test.go @@ -0,0 +1,2440 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "context" + "reflect" + "testing" + "time" + + agent "github.com/vdaas/vald/apis/grpc/agent/core" + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/pkg/gateway/meta/service" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want vald.ValdServer + } + type test struct { + name string + args args + want want + checkFunc func(want, vald.ValdServer) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got vald.ValdServer) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Exists(t *testing.T) { + type args struct { + ctx context.Context + meta *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Object_ID + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Object_ID, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Object_ID, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Exists(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Search(t *testing.T) { + type args struct { + ctx context.Context + req *payload.Search_Request + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.Search(test.args.ctx, test.args.req) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_SearchByID(t *testing.T) { + type args struct { + ctx context.Context + req *payload.Search_IDRequest + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + req: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.SearchByID(test.args.ctx, test.args.req) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_search(t *testing.T) { + type args struct { + ctx context.Context + cfg *payload.Search_Config + f func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Search_Response + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Search_Response, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Search_Response, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + cfg: nil, + f: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + cfg: nil, + f: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.search(test.args.ctx, test.args.cfg, test.args.f) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamSearch(t *testing.T) { + type args struct { + stream vald.Vald_StreamSearchServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamSearch(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamSearchByID(t *testing.T) { + type args struct { + stream vald.Vald_StreamSearchByIDServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamSearchByID(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Insert(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantCe *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCe *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCe, w.wantCe) { + return errors.Errorf("got = %v, want %v", gotCe, w.wantCe) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotCe, err := s.Insert(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, gotCe, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamInsert(t *testing.T) { + type args struct { + stream vald.Vald_StreamInsertServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamInsert(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiInsert(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiInsert(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Update(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.Update(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamUpdate(t *testing.T) { + type args struct { + stream vald.Vald_StreamUpdateServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamUpdate(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiUpdate(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiUpdate(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Upsert(t *testing.T) { + type args struct { + ctx context.Context + vec *payload.Object_Vector + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vec: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Upsert(test.args.ctx, test.args.vec) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamUpsert(t *testing.T) { + type args struct { + stream vald.Vald_StreamUpsertServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamUpsert(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiUpsert(t *testing.T) { + type args struct { + ctx context.Context + vecs *payload.Object_Vectors + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + vecs: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.MultiUpsert(test.args.ctx, test.args.vecs) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_Remove(t *testing.T) { + type args struct { + ctx context.Context + id *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + want *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + got, err := s.Remove(test.args.ctx, test.args.id) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamRemove(t *testing.T) { + type args struct { + stream vald.Vald_StreamRemoveServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamRemove(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_MultiRemove(t *testing.T) { + type args struct { + ctx context.Context + ids *payload.Object_IDs + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantRes *payload.Empty + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Empty, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotRes *payload.Empty, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotRes, w.wantRes) { + return errors.Errorf("got = %v, want %v", gotRes, w.wantRes) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + ids: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + ids: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotRes, err := s.MultiRemove(test.args.ctx, test.args.ids) + if err := test.checkFunc(test.want, gotRes, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_GetObject(t *testing.T) { + type args struct { + ctx context.Context + id *payload.Object_ID + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + wantVec *payload.Backup_MetaVector + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, *payload.Backup_MetaVector, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotVec *payload.Backup_MetaVector, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotVec, w.wantVec) { + return errors.Errorf("got = %v, want %v", gotVec, w.wantVec) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + id: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + gotVec, err := s.GetObject(test.args.ctx, test.args.id) + if err := test.checkFunc(test.want, gotVec, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_server_StreamGetObject(t *testing.T) { + type args struct { + stream vald.Vald_StreamGetObjectServer + } + type fields struct { + eg errgroup.Group + gateway service.Gateway + metadata service.Meta + backup service.Backup + timeout time.Duration + filter service.Filter + replica int + streamConcurrency int + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + stream: nil, + }, + fields: fields { + eg: nil, + gateway: nil, + metadata: nil, + backup: nil, + timeout: nil, + filter: nil, + replica: 0, + streamConcurrency: 0, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + s := &server{ + eg: test.fields.eg, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + timeout: test.fields.timeout, + filter: test.fields.filter, + replica: test.fields.replica, + streamConcurrency: test.fields.streamConcurrency, + } + + err := s.StreamGetObject(test.args.stream) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/meta/handler/grpc/option.go b/pkg/gateway/meta/handler/grpc/option.go new file mode 100644 index 00000000000..6e3493d87e1 --- /dev/null +++ b/pkg/gateway/meta/handler/grpc/option.go @@ -0,0 +1,103 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "time" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/timeutil" + "github.com/vdaas/vald/pkg/gateway/meta/service" +) + +type Option func(*server) + +var ( + defaultOpts = []Option{ + WithErrGroup(errgroup.Get()), + WithReplicationCount(3), + WithStreamConcurrency(20), + WithTimeout("5s"), + } +) + +func WithGateway(g service.Gateway) Option { + return func(s *server) { + if g != nil { + s.gateway = g + } + } +} + +func WithMeta(m service.Meta) Option { + return func(s *server) { + if m != nil { + s.metadata = m + } + } +} + +func WithBackup(b service.Backup) Option { + return func(s *server) { + if b != nil { + s.backup = b + } + } +} + +func WithFilters(filter service.Filter) Option { + return func(s *server) { + if filter != nil { + s.filter = filter + } + } +} + +func WithErrGroup(eg errgroup.Group) Option { + return func(s *server) { + if eg != nil { + s.eg = eg + } + } +} + +func WithTimeout(dur string) Option { + return func(s *server) { + d, err := timeutil.Parse(dur) + if err != nil { + d = time.Second * 10 + } + s.timeout = d + } +} + +func WithReplicationCount(rep int) Option { + return func(s *server) { + if rep > 1 { + s.replica = rep + } + } +} + +func WithStreamConcurrency(c int) Option { + return func(s *server) { + if c != 0 { + s.streamConcurrency = c + } + } +} diff --git a/pkg/gateway/meta/handler/grpc/option_test.go b/pkg/gateway/meta/handler/grpc/option_test.go new file mode 100644 index 00000000000..1197d5d5e50 --- /dev/null +++ b/pkg/gateway/meta/handler/grpc/option_test.go @@ -0,0 +1,931 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package grpc provides grpc server logic +package grpc + +import ( + "testing" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/pkg/gateway/meta/service" + + "go.uber.org/goleak" +) + +func TestWithGateway(t *testing.T) { + type T = interface{} + type args struct { + g service.Gateway + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + g: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + g: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithGateway(test.args.g) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithGateway(test.args.g) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMeta(t *testing.T) { + type T = interface{} + type args struct { + m service.Meta + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + m: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + m: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMeta(test.args.m) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMeta(test.args.m) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithBackup(t *testing.T) { + type T = interface{} + type args struct { + b service.Backup + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + b: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + b: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithBackup(test.args.b) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithBackup(test.args.b) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithFilters(t *testing.T) { + type T = interface{} + type args struct { + filter service.Filter + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + filter: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + filter: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithFilters(test.args.filter) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithFilters(test.args.filter) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithErrGroup(t *testing.T) { + type T = interface{} + type args struct { + eg errgroup.Group + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + eg: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithErrGroup(test.args.eg) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithErrGroup(test.args.eg) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithTimeout(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithTimeout(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithTimeout(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithReplicationCount(t *testing.T) { + type T = interface{} + type args struct { + rep int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + rep: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + rep: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithReplicationCount(test.args.rep) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithReplicationCount(test.args.rep) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithStreamConcurrency(t *testing.T) { + type T = interface{} + type args struct { + c int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + c: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + c: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithStreamConcurrency(test.args.c) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithStreamConcurrency(test.args.c) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/meta/handler/rest/handler.go b/pkg/gateway/meta/handler/rest/handler.go new file mode 100644 index 00000000000..c9b9b962660 --- /dev/null +++ b/pkg/gateway/meta/handler/rest/handler.go @@ -0,0 +1,131 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "net/http" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/net/http/dump" + "github.com/vdaas/vald/internal/net/http/json" +) + +type Handler interface { + Index(w http.ResponseWriter, r *http.Request) (int, error) + Exists(w http.ResponseWriter, r *http.Request) (int, error) + Search(w http.ResponseWriter, r *http.Request) (int, error) + SearchByID(w http.ResponseWriter, r *http.Request) (int, error) + Insert(w http.ResponseWriter, r *http.Request) (int, error) + MultiInsert(w http.ResponseWriter, r *http.Request) (int, error) + Update(w http.ResponseWriter, r *http.Request) (int, error) + MultiUpdate(w http.ResponseWriter, r *http.Request) (int, error) + Remove(w http.ResponseWriter, r *http.Request) (int, error) + MultiRemove(w http.ResponseWriter, r *http.Request) (int, error) + GetObject(w http.ResponseWriter, r *http.Request) (int, error) +} + +type handler struct { + vald vald.ValdServer +} + +func New(opts ...Option) Handler { + h := new(handler) + + for _, opt := range append(defaultOpts, opts...) { + opt(h) + } + return h +} + +func (h *handler) Index(w http.ResponseWriter, r *http.Request) (int, error) { + data := make(map[string]interface{}) + return json.Handler(w, r, &data, func() (interface{}, error) { + return dump.Request(nil, data, r) + }) +} + +func (h *handler) Search(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Search_Request + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Search(r.Context(), req) + }) +} + +func (h *handler) SearchByID(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Search_IDRequest + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.SearchByID(r.Context(), req) + }) +} + +func (h *handler) Insert(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vector + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Insert(r.Context(), req) + }) +} + +func (h *handler) MultiInsert(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vectors + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiInsert(r.Context(), req) + }) +} + +func (h *handler) Update(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vector + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Update(r.Context(), req) + }) +} + +func (h *handler) MultiUpdate(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_Vectors + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiUpdate(r.Context(), req) + }) +} + +func (h *handler) Remove(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Remove(r.Context(), req) + }) +} + +func (h *handler) MultiRemove(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_IDs + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.MultiRemove(r.Context(), req) + }) +} + +func (h *handler) GetObject(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.GetObject(r.Context(), req) + }) +} + +func (h *handler) Exists(w http.ResponseWriter, r *http.Request) (code int, err error) { + var req *payload.Object_ID + return json.Handler(w, r, &req, func() (interface{}, error) { + return h.vald.Exists(r.Context(), req) + }) +} diff --git a/pkg/gateway/meta/handler/rest/handler_test.go b/pkg/gateway/meta/handler/rest/handler_test.go new file mode 100644 index 00000000000..77e84d3000a --- /dev/null +++ b/pkg/gateway/meta/handler/rest/handler_test.go @@ -0,0 +1,1100 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "net/http" + "reflect" + "testing" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/internal/errors" + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want Handler + } + type test struct { + name string + args args + want want + checkFunc func(want, Handler) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got Handler) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Index(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + want int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + got, err := h.Index(test.args.w, test.args.r) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Search(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Search(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_SearchByID(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.SearchByID(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Insert(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Insert(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiInsert(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiInsert(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Update(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Update(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiUpdate(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiUpdate(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Remove(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Remove(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_MultiRemove(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.MultiRemove(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_GetObject(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.GetObject(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_handler_Exists(t *testing.T) { + type args struct { + w http.ResponseWriter + r *http.Request + } + type fields struct { + vald vald.ValdServer + } + type want struct { + wantCode int + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, int, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotCode int, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotCode, w.wantCode) { + return errors.Errorf("got = %v, want %v", gotCode, w.wantCode) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + w: nil, + r: nil, + }, + fields: fields { + vald: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + h := &handler{ + vald: test.fields.vald, + } + + gotCode, err := h.Exists(test.args.w, test.args.r) + if err := test.checkFunc(test.want, gotCode, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/meta/handler/rest/option.go b/pkg/gateway/meta/handler/rest/option.go new file mode 100644 index 00000000000..c684ad7ec83 --- /dev/null +++ b/pkg/gateway/meta/handler/rest/option.go @@ -0,0 +1,32 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import "github.com/vdaas/vald/apis/grpc/gateway/vald" + +type Option func(*handler) + +var ( + defaultOpts = []Option{} +) + +func WithVald(v vald.ValdServer) Option { + return func(h *handler) { + h.vald = v + } +} diff --git a/pkg/gateway/meta/handler/rest/option_test.go b/pkg/gateway/meta/handler/rest/option_test.go new file mode 100644 index 00000000000..57b72169c66 --- /dev/null +++ b/pkg/gateway/meta/handler/rest/option_test.go @@ -0,0 +1,138 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package rest provides rest api logic +package rest + +import ( + "testing" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "go.uber.org/goleak" +) + +func TestWithVald(t *testing.T) { + type T = interface{} + type args struct { + v vald.ValdServer + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + v: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + v: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithVald(test.args.v) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithVald(test.args.v) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/meta/router/option.go b/pkg/gateway/meta/router/option.go new file mode 100644 index 00000000000..ec8400aab06 --- /dev/null +++ b/pkg/gateway/meta/router/option.go @@ -0,0 +1,42 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "github.com/vdaas/vald/pkg/gateway/meta/handler/rest" +) + +type Option func(*router) + +var ( + defaultOpts = []Option{ + WithTimeout("3s"), + } +) + +func WithHandler(h rest.Handler) Option { + return func(r *router) { + r.handler = h + } +} + +func WithTimeout(timeout string) Option { + return func(r *router) { + r.timeout = timeout + } +} diff --git a/pkg/gateway/meta/router/option_test.go b/pkg/gateway/meta/router/option_test.go new file mode 100644 index 00000000000..1f623dc60df --- /dev/null +++ b/pkg/gateway/meta/router/option_test.go @@ -0,0 +1,252 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "testing" + + "github.com/vdaas/vald/pkg/gateway/meta/handler/rest" + + "go.uber.org/goleak" +) + +func TestWithHandler(t *testing.T) { + type T = interface{} + type args struct { + h rest.Handler + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + h: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + h: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithHandler(test.args.h) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithHandler(test.args.h) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithTimeout(t *testing.T) { + type T = interface{} + type args struct { + timeout string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + timeout: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + timeout: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithTimeout(test.args.timeout) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithTimeout(test.args.timeout) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/meta/router/router.go b/pkg/gateway/meta/router/router.go new file mode 100644 index 00000000000..e8789ff2273 --- /dev/null +++ b/pkg/gateway/meta/router/router.go @@ -0,0 +1,130 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "net/http" + + "github.com/vdaas/vald/internal/net/http/routing" + "github.com/vdaas/vald/pkg/gateway/meta/handler/rest" +) + +type router struct { + handler rest.Handler + timeout string +} + +// New returns REST route&method information from handler interface +func New(opts ...Option) http.Handler { + r := new(router) + + for _, opt := range append(defaultOpts, opts...) { + opt(r) + } + + h := r.handler + + return routing.New( + routing.WithRoutes([]routing.Route{ + { + "Index", + []string{ + http.MethodGet, + }, + "/", + h.Index, + }, + { + "Search", + []string{ + http.MethodPost, + }, + "/search", + h.Search, + }, + { + "Search By ID", + []string{ + http.MethodGet, + }, + "/search/{id}", + h.SearchByID, + }, + { + "Insert", + []string{ + http.MethodPost, + }, + "/insert", + h.Insert, + }, + { + "Multiple Insert", + []string{ + http.MethodPost, + }, + "/insert/multi", + h.MultiInsert, + }, + { + "Update", + []string{ + http.MethodPost, + http.MethodPatch, + http.MethodPut, + }, + "/update", + h.Update, + }, + { + "Multiple Update", + []string{ + http.MethodPost, + http.MethodPatch, + http.MethodPut, + }, + "/update/multi", + h.MultiUpdate, + }, + { + "Remove", + []string{ + http.MethodDelete, + }, + "/delete/{id}", + h.Remove, + }, + { + "Multiple Remove", + []string{ + http.MethodDelete, + http.MethodPost, + }, + "/delete/multi", + h.MultiRemove, + }, + { + "GetObject", + []string{ + http.MethodGet, + }, + "/object/{id}", + h.GetObject, + }, + }...)) +} diff --git a/pkg/gateway/meta/router/router_test.go b/pkg/gateway/meta/router/router_test.go new file mode 100644 index 00000000000..876b9574c48 --- /dev/null +++ b/pkg/gateway/meta/router/router_test.go @@ -0,0 +1,96 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package router provides implementation of Go API for routing http Handler wrapped by rest.Func +package router + +import ( + "net/http" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errors" +) + +func TestNew(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + want http.Handler + } + type test struct { + name string + args args + want want + checkFunc func(want, http.Handler) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got http.Handler) error { + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := New(test.args.opts...) + if err := test.checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/meta/service/doc.go b/pkg/gateway/meta/service/doc.go new file mode 100644 index 00000000000..c13956cbbe3 --- /dev/null +++ b/pkg/gateway/meta/service/doc.go @@ -0,0 +1,18 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service manages the main logic of server. +package service diff --git a/pkg/gateway/meta/service/meta.go b/pkg/gateway/meta/service/meta.go new file mode 100644 index 00000000000..14160f9931e --- /dev/null +++ b/pkg/gateway/meta/service/meta.go @@ -0,0 +1,490 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service provides meta service +package service + +import ( + "context" + "reflect" + + gmeta "github.com/vdaas/vald/apis/grpc/meta" + "github.com/vdaas/vald/apis/grpc/payload" + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/status" + "github.com/vdaas/vald/internal/observability/trace" +) + +type Meta interface { + Start(ctx context.Context) (<-chan error, error) + Exists(context.Context, string) (bool, error) + GetMeta(context.Context, string) (string, error) + GetMetas(context.Context, ...string) ([]string, error) + GetUUID(context.Context, string) (string, error) + GetUUIDs(context.Context, ...string) ([]string, error) + SetUUIDandMeta(context.Context, string, string) error + SetUUIDandMetas(context.Context, map[string]string) error + DeleteMeta(context.Context, string) (string, error) + DeleteMetas(context.Context, ...string) ([]string, error) + DeleteUUID(context.Context, string) (string, error) + DeleteUUIDs(context.Context, ...string) ([]string, error) +} + +type meta struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string +} + +const ( + uuidCacheKeyPref = "uuid-" + metaCacheKeyPref = "meta-" +) + +func NewMeta(opts ...Option) (mi Meta, err error) { + m := new(meta) + for _, opt := range append(defaultOpts, opts...) { + if err = opt(m); err != nil { + return nil, errors.ErrOptionFailed(err, reflect.ValueOf(opt)) + } + } + if m.enableCache { + if m.cache == nil { + m.cache, err = cache.New( + cache.WithExpireDuration(m.expireDuration), + cache.WithExpireCheckDuration(m.expireCheckDuration), + ) + if err != nil { + return nil, err + } + } + } + + return m, nil +} + +func (m *meta) Start(ctx context.Context) (<-chan error, error) { + if m.enableCache && m.cache != nil { + m.cache.Start(ctx) + } + return m.client.StartConnectionMonitor(ctx) +} + +func (m *meta) Exists(ctx context.Context, meta string) (bool, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.Exists") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + _, ok := m.cache.Get(uuidCacheKeyPref + meta) + if ok { + return true, nil + } + } + key, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + key, err := gmeta.NewMetaClient(conn).GetMetaInverse(ctx, &payload.Meta_Val{ + Val: meta, + }, copts...) + if err != nil { + if status.Code(err) == status.NotFound { + return "", nil + } + return nil, err + } + return key.GetKey(), nil + }) + if err != nil { + return false, err + } + + k := key.(string) + if k == "" { + return false, nil + } + + if m.enableCache { + m.cache.Set(uuidCacheKeyPref+meta, k) + m.cache.Set(metaCacheKeyPref+k, meta) + } + return true, nil +} + +func (m *meta) GetMeta(ctx context.Context, uuid string) (v string, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetMeta") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + data, ok := m.cache.Get(metaCacheKeyPref + uuid) + if ok { + return data.(string), nil + } + } + val, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + val, err := gmeta.NewMetaClient(conn).GetMeta(ctx, &payload.Meta_Key{ + Key: uuid, + }, copts...) + if err != nil { + return nil, err + } + return val.GetVal(), nil + }) + if err != nil { + return "", err + } + v = val.(string) + + if m.enableCache { + m.cache.Set(metaCacheKeyPref+uuid, v) + m.cache.Set(uuidCacheKeyPref+v, uuid) + } + return v, nil +} + +func (m *meta) GetMetas(ctx context.Context, uuids ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetMetas") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + metas, ok := func() (metas []string, ok bool) { + for _, uuid := range uuids { + data, ok := m.cache.Get(metaCacheKeyPref + uuid) + if !ok { + return nil, false + } + metas = append(metas, data.(string)) + } + return metas, true + }() + if ok { + return metas, nil + } + } + vals, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + vals, err := gmeta.NewMetaClient(conn).GetMetas(ctx, &payload.Meta_Keys{ + Keys: uuids, + }, copts...) + if vals != nil { + return vals.GetVals(), err + } + return nil, err + }) + if vals != nil { + vs, ok := vals.([]string) + if ok { + if m.enableCache { + for i, v := range vs { + uuid := uuids[i] + m.cache.Set(metaCacheKeyPref+uuid, v) + m.cache.Set(uuidCacheKeyPref+v, uuid) + } + } + return vs, err + } + } + return nil, err +} + +func (m *meta) GetUUID(ctx context.Context, meta string) (k string, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetUUID") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + data, ok := m.cache.Get(uuidCacheKeyPref + meta) + if ok { + return data.(string), nil + } + } + key, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + key, err := gmeta.NewMetaClient(conn).GetMetaInverse(ctx, &payload.Meta_Val{ + Val: meta, + }, copts...) + if err != nil { + return nil, err + } + return key.GetKey(), nil + }) + if err != nil { + return "", err + } + + k = key.(string) + if m.enableCache { + m.cache.Set(uuidCacheKeyPref+meta, k) + m.cache.Set(metaCacheKeyPref+k, meta) + } + return k, nil +} + +func (m *meta) GetUUIDs(ctx context.Context, metas ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.GetUUIDs") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + uuids, ok := func() (uuids []string, ok bool) { + for _, meta := range metas { + data, ok := m.cache.Get(uuidCacheKeyPref + meta) + if !ok { + return nil, false + } + uuids = append(uuids, data.(string)) + } + return uuids, true + }() + if ok { + return uuids, nil + } + } + keys, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + keys, err := gmeta.NewMetaClient(conn).GetMetasInverse(ctx, &payload.Meta_Vals{ + Vals: metas, + }, copts...) + if keys != nil { + return keys.GetKeys(), err + } + return nil, err + }) + if keys != nil { + ks, ok := keys.([]string) + if ok { + if m.enableCache { + for i, k := range ks { + meta := metas[i] + m.cache.Set(uuidCacheKeyPref+meta, k) + m.cache.Set(metaCacheKeyPref+k, meta) + } + } + return ks, err + } + } + return nil, err +} + +func (m *meta) SetUUIDandMeta(ctx context.Context, uuid, meta string) (err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.SetUUIDandMeta") + defer func() { + if span != nil { + span.End() + } + }() + + _, err = m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + _, err := gmeta.NewMetaClient(conn).SetMeta(ctx, &payload.Meta_KeyVal{ + Key: uuid, + Val: meta, + }, copts...) + + return nil, err + }) + if err != nil { + return err + } + + if m.enableCache { + m.cache.Set(uuidCacheKeyPref+meta, uuid) + m.cache.Set(metaCacheKeyPref+uuid, meta) + } + return nil +} + +func (m *meta) SetUUIDandMetas(ctx context.Context, kvs map[string]string) (err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.SetUUIDandMetas") + defer func() { + if span != nil { + span.End() + } + }() + + data := make([]*payload.Meta_KeyVal, 0, len(kvs)) + for uuid, meta := range kvs { + data = append(data, &payload.Meta_KeyVal{ + Key: uuid, + Val: meta, + }) + } + _, err = m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + _, err := gmeta.NewMetaClient(conn).SetMetas(ctx, &payload.Meta_KeyVals{ + Kvs: data, + }, copts...) + + return nil, err + }) + if err != nil { + return err + } + + if m.enableCache { + for uuid, meta := range kvs { + m.cache.Set(uuidCacheKeyPref+meta, uuid) + m.cache.Set(metaCacheKeyPref+uuid, meta) + } + } + return nil +} + +func (m *meta) DeleteMeta(ctx context.Context, uuid string) (v string, err error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteMeta") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + meta, ok := m.cache.GetAndDelete(metaCacheKeyPref + uuid) + if ok { + m.cache.Delete(uuidCacheKeyPref + meta.(string)) + } + } + val, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + val, err := gmeta.NewMetaClient(conn).DeleteMeta(ctx, &payload.Meta_Key{ + Key: uuid, + }, copts...) + if err != nil { + return nil, err + } + return val.GetVal(), nil + }) + if err != nil { + return "", err + } + return val.(string), nil +} + +func (m *meta) DeleteMetas(ctx context.Context, uuids ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteMetas") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + for _, uuid := range uuids { + meta, ok := m.cache.GetAndDelete(metaCacheKeyPref + uuid) + if ok { + m.cache.Delete(uuidCacheKeyPref + meta.(string)) + } + } + } + vals, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + vals, err := gmeta.NewMetaClient(conn).DeleteMetas(ctx, &payload.Meta_Keys{ + Keys: uuids, + }, copts...) + if err != nil { + return nil, err + } + return vals.GetVals(), nil + }) + if err != nil { + return nil, err + } + return vals.([]string), nil +} + +func (m *meta) DeleteUUID(ctx context.Context, meta string) (string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteUUID") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + uuid, ok := m.cache.GetAndDelete(uuidCacheKeyPref + meta) + if ok { + m.cache.Delete(metaCacheKeyPref + uuid.(string)) + } + } + key, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + key, err := gmeta.NewMetaClient(conn).DeleteMetaInverse(ctx, &payload.Meta_Val{ + Val: meta, + }, copts...) + if err != nil { + return nil, err + } + return key.GetKey(), nil + }) + if err != nil { + return "", err + } + return key.(string), nil +} + +func (m *meta) DeleteUUIDs(ctx context.Context, metas ...string) ([]string, error) { + ctx, span := trace.StartSpan(ctx, "vald/gateway-vald/service/Meta.DeleteUUIDs") + defer func() { + if span != nil { + span.End() + } + }() + + if m.enableCache { + for _, meta := range metas { + uuid, ok := m.cache.GetAndDelete(uuidCacheKeyPref + meta) + if ok { + m.cache.Delete(metaCacheKeyPref + uuid.(string)) + } + } + } + keys, err := m.client.Do(ctx, m.addr, func(ctx context.Context, + conn *grpc.ClientConn, copts ...grpc.CallOption) (interface{}, error) { + keys, err := gmeta.NewMetaClient(conn).DeleteMetasInverse(ctx, &payload.Meta_Vals{ + Vals: metas, + }, copts...) + if err != nil { + return nil, err + } + return keys.GetKeys(), nil + }) + if err != nil { + return nil, err + } + return keys.([]string), nil +} diff --git a/pkg/gateway/meta/service/meta_test.go b/pkg/gateway/meta/service/meta_test.go new file mode 100644 index 00000000000..e2bc28d6115 --- /dev/null +++ b/pkg/gateway/meta/service/meta_test.go @@ -0,0 +1,1429 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service provides meta service +package service + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + + "go.uber.org/goleak" +) + +func TestNewMeta(t *testing.T) { + type args struct { + opts []Option + } + type want struct { + wantMi Meta + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, Meta, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotMi Meta, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotMi, w.wantMi) { + return errors.Errorf("got = %v, want %v", gotMi, w.wantMi) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + opts: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotMi, err := NewMeta(test.args.opts...) + if err := test.checkFunc(test.want, gotMi, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_Exists(t *testing.T) { + type args struct { + ctx context.Context + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want bool + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, bool, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got bool, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.Exists(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetMeta(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + wantV string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotV string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotV, w.wantV) { + return errors.Errorf("got = %v, want %v", gotV, w.wantV) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + gotV, err := m.GetMeta(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotV, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetMetas(t *testing.T) { + type args struct { + ctx context.Context + uuids []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.GetMetas(test.args.ctx, test.args.uuids...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetUUID(t *testing.T) { + type args struct { + ctx context.Context + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + wantK string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotK string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotK, w.wantK) { + return errors.Errorf("got = %v, want %v", gotK, w.wantK) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + gotK, err := m.GetUUID(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, gotK, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_GetUUIDs(t *testing.T) { + type args struct { + ctx context.Context + metas []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.GetUUIDs(test.args.ctx, test.args.metas...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_SetUUIDandMeta(t *testing.T) { + type args struct { + ctx context.Context + uuid string + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + err := m.SetUUIDandMeta(test.args.ctx, test.args.uuid, test.args.meta) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_SetUUIDandMetas(t *testing.T) { + type args struct { + ctx context.Context + kvs map[string]string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + kvs: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + kvs: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + err := m.SetUUIDandMetas(test.args.ctx, test.args.kvs) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteMeta(t *testing.T) { + type args struct { + ctx context.Context + uuid string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + wantV string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotV string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotV, w.wantV) { + return errors.Errorf("got = %v, want %v", gotV, w.wantV) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuid: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + gotV, err := m.DeleteMeta(test.args.ctx, test.args.uuid) + if err := test.checkFunc(test.want, gotV, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteMetas(t *testing.T) { + type args struct { + ctx context.Context + uuids []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + uuids: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.DeleteMetas(test.args.ctx, test.args.uuids...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteUUID(t *testing.T) { + type args struct { + ctx context.Context + meta string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + meta: "", + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.DeleteUUID(test.args.ctx, test.args.meta) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_meta_DeleteUUIDs(t *testing.T) { + type args struct { + ctx context.Context + metas []string + } + type fields struct { + addr string + client grpc.Client + cache cache.Cache + enableCache bool + expireCheckDuration string + expireDuration string + } + type want struct { + want []string + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, []string, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got []string, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + metas: nil, + }, + fields: fields { + addr: "", + client: nil, + cache: nil, + enableCache: false, + expireCheckDuration: "", + expireDuration: "", + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + m := &meta{ + addr: test.fields.addr, + client: test.fields.client, + cache: test.fields.cache, + enableCache: test.fields.enableCache, + expireCheckDuration: test.fields.expireCheckDuration, + expireDuration: test.fields.expireDuration, + } + + got, err := m.DeleteUUIDs(test.args.ctx, test.args.metas...) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/meta/service/option.go b/pkg/gateway/meta/service/option.go new file mode 100644 index 00000000000..efe05ce7551 --- /dev/null +++ b/pkg/gateway/meta/service/option.go @@ -0,0 +1,97 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "fmt" + + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/timeutil" +) + +type Option func(m *meta) error + +var ( + defaultOpts = []Option{ + WithMetaCacheEnabled(true), + WithMetaCacheExpireDuration("30m"), + WithMetaCacheExpiredCheckDuration("2m"), + } +) + +func WithMetaAddr(addr string) Option { + return func(m *meta) error { + m.addr = addr + return nil + } +} + +func WithMetaHostPort(host string, port int) Option { + return func(m *meta) error { + m.addr = fmt.Sprintf("%s:%d", host, port) + return nil + } +} + +func WithMetaClient(client grpc.Client) Option { + return func(m *meta) error { + if client != nil { + m.client = client + } + return nil + } +} + +func WithMetaCacheEnabled(flg bool) Option { + return func(m *meta) error { + m.enableCache = flg + return nil + } +} + +func WithMetaCache(c cache.Cache) Option { + return func(m *meta) error { + if c != nil { + m.cache = c + } + return nil + } +} + +func WithMetaCacheExpireDuration(dur string) Option { + return func(m *meta) error { + _, err := timeutil.Parse(dur) + if err != nil { + return err + } + m.expireDuration = dur + return nil + } +} + +func WithMetaCacheExpiredCheckDuration(dur string) Option { + return func(m *meta) error { + _, err := timeutil.Parse(dur) + if err != nil { + return err + } + m.expireCheckDuration = dur + return nil + } +} diff --git a/pkg/gateway/meta/service/option_test.go b/pkg/gateway/meta/service/option_test.go new file mode 100644 index 00000000000..001b03c4484 --- /dev/null +++ b/pkg/gateway/meta/service/option_test.go @@ -0,0 +1,820 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Package service +package service + +import ( + "testing" + + "github.com/vdaas/vald/internal/cache" + "github.com/vdaas/vald/internal/net/grpc" + "go.uber.org/goleak" +) + +func TestWithMetaAddr(t *testing.T) { + type T = interface{} + type args struct { + addr string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + addr: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaAddr(test.args.addr) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaAddr(test.args.addr) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaHostPort(t *testing.T) { + type T = interface{} + type args struct { + host string + port int + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + host: "", + port: 0, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + host: "", + port: 0, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaHostPort(test.args.host, test.args.port) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaHostPort(test.args.host, test.args.port) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaClient(t *testing.T) { + type T = interface{} + type args struct { + client grpc.Client + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + client: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaClient(test.args.client) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaClient(test.args.client) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCacheEnabled(t *testing.T) { + type T = interface{} + type args struct { + flg bool + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + flg: false, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + flg: false, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCacheEnabled(test.args.flg) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCacheEnabled(test.args.flg) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCache(t *testing.T) { + type T = interface{} + type args struct { + c cache.Cache + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + c: nil, + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCache(test.args.c) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCache(test.args.c) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCacheExpireDuration(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCacheExpireDuration(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCacheExpireDuration(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} + +func TestWithMetaCacheExpiredCheckDuration(t *testing.T) { + type T = interface{} + type args struct { + dur string + } + type want struct { + obj *T + // Uncomment this line if the option returns an error, otherwise delete it + // err error + } + type test struct { + name string + args args + want want + // Use the first line if the option returns an error. otherwise use the second line + // checkFunc func(want, *T, error) error + // checkFunc func(want, *T) error + beforeFunc func(args) + afterFunc func(args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.obj) + } + return nil + } + */ + + // Uncomment this block if the option do not returns an error, otherwise delete it + /* + defaultCheckFunc := func(w want, obj *T) error { + if !reflect.DeepEqual(obj, w.obj) { + return errors.Errorf("got = %v, want %v", obj, w.c) + } + return nil + } + */ + + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + dur: "", + }, + want: want { + obj: new(T), + }, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + got := WithMetaCacheExpiredCheckDuration(test.args.dur) + obj := new(T) + if err := test.checkFunc(test.want, obj, got(obj)); err != nil { + tt.Errorf("error = %v", err) + } + */ + + // Uncomment this block if the option returns an error, otherwise delete it + /* + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + got := WithMetaCacheExpiredCheckDuration(test.args.dur) + obj := new(T) + got(obj) + if err := test.checkFunc(tt.want, obj); err != nil { + tt.Errorf("error = %v", err) + } + */ + }) + } +} diff --git a/pkg/gateway/meta/usecase/vald.go b/pkg/gateway/meta/usecase/vald.go new file mode 100644 index 00000000000..dc31c1f0a5f --- /dev/null +++ b/pkg/gateway/meta/usecase/vald.go @@ -0,0 +1,202 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package usecase + +import ( + "context" + + "github.com/vdaas/vald/apis/grpc/gateway/vald" + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/net/grpc" + "github.com/vdaas/vald/internal/net/grpc/metric" + "github.com/vdaas/vald/internal/observability" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/safety" + "github.com/vdaas/vald/internal/servers/server" + "github.com/vdaas/vald/internal/servers/starter" + "github.com/vdaas/vald/pkg/gateway/meta/config" + handler "github.com/vdaas/vald/pkg/gateway/meta/handler/grpc" + "github.com/vdaas/vald/pkg/gateway/meta/handler/rest" + "github.com/vdaas/vald/pkg/gateway/meta/router" + "github.com/vdaas/vald/pkg/gateway/meta/service" +) + +type run struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + metadata service.Meta +} + +func New(cfg *config.Data) (r runner.Runner, err error) { + eg := errgroup.Get() + + var metadata service.Meta + + metadataClientOptions := append( + cfg.Meta.Client.Opts(), + grpc.WithErrGroup(eg), + ) + + var obs observability.Observability + if cfg.Observability.Enabled { + obs, err = observability.NewWithConfig(cfg.Observability) + if err != nil { + return nil, err + } + metadataClientOptions = append( + metadataClientOptions, + grpc.WithDialOptions( + grpc.WithStatsHandler(metric.NewClientHandler()), + ), + ) + } + + if addrs := cfg.Meta.Client.Addrs; len(addrs) == 0 { + return nil, errors.ErrInvalidMetaDataConfig + } + metadata, err = service.NewMeta( + service.WithMetaAddr(cfg.Meta.Client.Addrs[0]), + service.WithMetaClient( + grpc.New(metadataClientOptions...), + ), + service.WithMetaCacheEnabled(cfg.Meta.EnableCache), + service.WithMetaCacheExpireDuration(cfg.Meta.CacheExpiration), + service.WithMetaCacheExpiredCheckDuration(cfg.Meta.ExpiredCacheCheckDuration), + ) + if err != nil { + return nil, err + } + + v := handler.New( + handler.WithMeta(metadata), + handler.WithErrGroup(eg), + handler.WithStreamConcurrency(cfg.Server.GetGRPCStreamConcurrency()), + ) + + grpcServerOptions := []server.Option{ + server.WithGRPCRegistFunc(func(srv *grpc.Server) { + vald.RegisterValdServer(srv, v) + }), + server.WithPreStopFunction(func() error { + // TODO notify another gateway and scheduler + return nil + }), + } + + if cfg.Observability.Enabled { + grpcServerOptions = append( + grpcServerOptions, + server.WithGRPCOption( + grpc.StatsHandler(metric.NewServerHandler()), + ), + ) + } + + srv, err := starter.New( + starter.WithConfig(cfg.Server), + starter.WithREST(func(sc *config.Server) []server.Option { + return []server.Option{ + server.WithHTTPHandler( + router.New( + router.WithHandler( + rest.New( + rest.WithVald(v), + ), + ), + ), + ), + } + }), + starter.WithGRPC(func(sc *config.Server) []server.Option { + return grpcServerOptions + }), + // TODO add GraphQL handler + ) + if err != nil { + return nil, err + } + + return &run{ + eg: eg, + cfg: cfg, + server: srv, + observability: obs, + metadata: metadata, + }, nil +} + +func (r *run) PreStart(ctx context.Context) error { + if r.observability != nil { + return r.observability.PreStart(ctx) + } + return nil +} + +func (r *run) Start(ctx context.Context) (<-chan error, error) { + ech := make(chan error, 6) + var mech, sech, oech <-chan error + var err error + if r.observability != nil { + oech = r.observability.Start(ctx) + } + if r.metadata != nil { + mech, err = r.metadata.Start(ctx) + if err != nil { + close(ech) + return nil, err + } + } + sech = r.server.ListenAndServe(ctx) + r.eg.Go(safety.RecoverFunc(func() (err error) { + defer close(ech) + for { + select { + case <-ctx.Done(): + return ctx.Err() + case err = <-oech: + case err = <-mech: + case err = <-sech: + } + if err != nil { + select { + case <-ctx.Done(): + return ctx.Err() + case ech <- err: + } + } + } + })) + return ech, nil +} + +func (r *run) PreStop(ctx context.Context) error { + return nil +} + +func (r *run) Stop(ctx context.Context) error { + if r.observability != nil { + r.observability.Stop(ctx) + } + return r.server.Shutdown(ctx) +} + +func (r *run) PostStop(ctx context.Context) error { + return nil +} diff --git a/pkg/gateway/meta/usecase/vald_test.go b/pkg/gateway/meta/usecase/vald_test.go new file mode 100644 index 00000000000..92effb2665b --- /dev/null +++ b/pkg/gateway/meta/usecase/vald_test.go @@ -0,0 +1,672 @@ +// +// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt ) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package usecase + +import ( + "context" + "reflect" + "testing" + + "github.com/vdaas/vald/internal/errgroup" + "github.com/vdaas/vald/internal/errors" + "github.com/vdaas/vald/internal/observability" + "github.com/vdaas/vald/internal/runner" + "github.com/vdaas/vald/internal/servers/starter" + "github.com/vdaas/vald/pkg/gateway/meta/config" + "github.com/vdaas/vald/pkg/gateway/meta/service" + + "go.uber.org/goleak" +) + +func TestNew(t *testing.T) { + type args struct { + cfg *config.Data + } + type want struct { + wantR runner.Runner + err error + } + type test struct { + name string + args args + want want + checkFunc func(want, runner.Runner, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, gotR runner.Runner, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(gotR, w.wantR) { + return errors.Errorf("got = %v, want %v", gotR, w.wantR) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + cfg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + cfg: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + + gotR, err := New(test.args.cfg) + if err := test.checkFunc(test.want, gotR, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PreStart(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PreStart(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_Start(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + want <-chan error + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, <-chan error, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got <-chan error, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want %v", got, w.want) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + got, err := r.Start(test.args.ctx) + if err := test.checkFunc(test.want, got, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PreStop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PreStop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_Stop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.Stop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} + +func Test_run_PostStop(t *testing.T) { + type args struct { + ctx context.Context + } + type fields struct { + eg errgroup.Group + cfg *config.Data + server starter.Server + observability observability.Observability + filter service.Filter + gateway service.Gateway + metadata service.Meta + backup service.Backup + } + type want struct { + err error + } + type test struct { + name string + args args + fields fields + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, err error) error { + if !errors.Is(err, w.err) { + return errors.Errorf("got error = %v, want %v", err, w.err) + } + return nil + } + tests := []test{ + // TODO test cases + /* + { + name: "test_case_1", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + }, + */ + + // TODO test cases + /* + func() test { + return test { + name: "test_case_2", + args: args { + ctx: nil, + }, + fields: fields { + eg: nil, + cfg: nil, + server: nil, + observability: nil, + filter: nil, + gateway: nil, + metadata: nil, + backup: nil, + }, + want: want{}, + checkFunc: defaultCheckFunc, + } + }(), + */ + } + + for _, test := range tests { + t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(t) + if test.beforeFunc != nil { + test.beforeFunc(test.args) + } + if test.afterFunc != nil { + defer test.afterFunc(test.args) + } + if test.checkFunc == nil { + test.checkFunc = defaultCheckFunc + } + r := &run{ + eg: test.fields.eg, + cfg: test.fields.cfg, + server: test.fields.server, + observability: test.fields.observability, + filter: test.fields.filter, + gateway: test.fields.gateway, + metadata: test.fields.metadata, + backup: test.fields.backup, + } + + err := r.PostStop(test.args.ctx) + if err := test.checkFunc(test.want, err); err != nil { + tt.Errorf("error = %v", err) + } + + }) + } +} diff --git a/pkg/gateway/vald/handler/grpc/handler.go b/pkg/gateway/vald/handler/grpc/handler.go index 7dac4a2f01c..5481288e61a 100644 --- a/pkg/gateway/vald/handler/grpc/handler.go +++ b/pkg/gateway/vald/handler/grpc/handler.go @@ -87,6 +87,9 @@ func (s *server) Search(ctx context.Context, req *payload.Search_Request) (res * span.End() } }() + if len(req.Vector) < 2 { + return nil, errors.ErrInvalidDimensionSize(len(req.Vector), 0) + } return s.search(ctx, req.GetConfig(), func(ctx context.Context, ac agent.AgentClient, copts ...grpc.CallOption) (*payload.Search_Response, error) { return ac.Search(ctx, req, copts...) @@ -126,6 +129,7 @@ func (s *server) search(ctx context.Context, cfg *payload.Search_Config, span.End() } }() + maxDist := uint32(math.MaxUint32) num := int(cfg.GetNum()) res = new(payload.Search_Response) @@ -290,6 +294,9 @@ func (s *server) Insert(ctx context.Context, vec *payload.Object_Vector) (ce *pa span.End() } }() + if len(vec.Vector) < 2 { + return nil, errors.ErrInvalidDimensionSize(len(vec.Vector), 0) + } meta := vec.GetId() exists, err := s.metadata.Exists(ctx, meta) if err != nil {