From 096acf5f655bc4814caafc974154f21281e91615 Mon Sep 17 00:00:00 2001 From: Kosuke Morimoto Date: Mon, 9 May 2022 18:33:08 +0900 Subject: [PATCH 1/7] add drafts of remove test cases Signed-off-by: Kosuke Morimoto --- .../core/ngt/handler/grpc/handler_test.go | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pkg/agent/core/ngt/handler/grpc/handler_test.go b/pkg/agent/core/ngt/handler/grpc/handler_test.go index be8f10a27a..3f0ec3333e 100644 --- a/pkg/agent/core/ngt/handler/grpc/handler_test.go +++ b/pkg/agent/core/ngt/handler/grpc/handler_test.go @@ -4651,6 +4651,33 @@ func Test_server_Remove(t *testing.T) { } return nil } + + /* + Remove test cases ( focus on ID(string), only test float32 ): + - Equivalence Class Testing ( 1000 vectors inserted before a search ) + - case 1.1: success remove vector + - case 2.1: fail remove with non-existent ID + - Boundary Value Testing ( 1000 vectors inserted before a search ) + - case 1.1: fail remove with "" + - case 2.1: success remove with ^@ + - case 2.2: success remove with ^I + - case 2.3: success remove with ^J + - case 2.4: success remove with ^M + - case 2.5: success remove with ^[ + - case 2.6: success remove with ^? + - case 3.1: success remove with utf-8 ID from utf-8 index + - case 3.2: fail remove with utf-8 ID from s-jis index + - case 3.3: fail remove with utf-8 ID from euc-jp index + - case 3.4: fail remove with s-jis ID from utf-8 index + - case 3.5: success remove with s-jis ID from s-jis index + - case 3.6: fail remove with s-jis ID from euc-jp index + - case 3.4: fail remove with euc-jp ID from utf-8 index + - case 3.5: fail remove with euc-jp ID from s-jis index + - case 3.6: success remove with euc-jp ID from euc-jp index + - case 4.1: success remove with 😀 + - Decision Table Testing + - NONE + */ tests := []test{ // TODO test cases /* From 5b3ab739114f62760c67da1aaca894cb0c415664 Mon Sep 17 00:00:00 2001 From: Kosuke Morimoto Date: Wed, 11 May 2022 00:36:22 +0900 Subject: [PATCH 2/7] implement remove handler test cases Signed-off-by: Kosuke Morimoto --- .../core/ngt/handler/grpc/handler_test.go | 372 ++++++++++++++---- 1 file changed, 303 insertions(+), 69 deletions(-) diff --git a/pkg/agent/core/ngt/handler/grpc/handler_test.go b/pkg/agent/core/ngt/handler/grpc/handler_test.go index 3f0ec3333e..94086259a3 100644 --- a/pkg/agent/core/ngt/handler/grpc/handler_test.go +++ b/pkg/agent/core/ngt/handler/grpc/handler_test.go @@ -4618,40 +4618,107 @@ func Test_server_MultiUpsert(t *testing.T) { func Test_server_Remove(t *testing.T) { t.Parallel() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + type args struct { - ctx context.Context - req *payload.Remove_Request - } - type fields struct { - name string - ip string - ngt service.NGT - eg errgroup.Group - streamConcurrency int + ctx context.Context + indexId string + removeId string } type want struct { - wantRes *payload.Object_Location - err error + code codes.Code + wantUuid string + err error } type test struct { name string args args - fields fields want want checkFunc func(want, *payload.Object_Location, error) error - beforeFunc func(args) + beforeFunc func(args) (Server, error) afterFunc func(args) } defaultCheckFunc := func(w want, gotRes *payload.Object_Location, err error) error { - if !errors.Is(err, w.err) { - return errors.Errorf("got_error: \"%#v\",\n\t\t\t\twant: \"%#v\"", err, w.err) - } - if !reflect.DeepEqual(gotRes, w.wantRes) { - return errors.Errorf("got: \"%#v\",\n\t\t\t\twant: \"%#v\"", gotRes, w.wantRes) + if err != nil { + st, ok := status.FromError(err) + if !ok { + errors.Errorf("got error cannot convert to Status: \"%#v\"", err) + } + if st.Code() != w.code { + return errors.Errorf("got code: \"%#v\",\n\t\t\t\twant code: \"%#v\"", st.Code(), w.code) + } + } else { + if !reflect.DeepEqual(gotRes.Uuid, w.wantUuid) { + return errors.Errorf("got: \"%#v\",\n\t\t\t\twant: \"%#v\"", gotRes, w.wantUuid) + } } return nil } + const ( + insertNum = 1000 + ) + + defaultNgtConfig := &config.NGT{ + Dimension: 128, + DistanceType: ngt.L2.String(), + ObjectType: ngt.Float.String(), + CreationEdgeSize: 60, + SearchEdgeSize: 20, + KVSDB: &config.KVSDB{ + Concurrency: 10, + }, + VQueue: &config.VQueue{ + InsertBufferPoolSize: 1000, + DeleteBufferPoolSize: 1000, + }, + } + defaultBeforeFunc := func(a args) (Server, error) { + eg, ctx := errgroup.New(a.ctx) + ngt, err := service.New(defaultNgtConfig, service.WithErrGroup(eg), service.WithEnableInMemoryMode(true)) + if err != nil { + return nil, err + } + + s, err := New(WithErrGroup(eg), WithNGT(ngt)) + if err != nil { + return nil, err + } + + reqs := make([]*payload.Insert_Request, insertNum) + for i, v := range vector.GaussianDistributedFloat32VectorGenerator(insertNum, defaultNgtConfig.Dimension) { + reqs[i] = &payload.Insert_Request{ + Vector: &payload.Object_Vector{ + Id: strconv.Itoa(i), + Vector: v, + }, + Config: &payload.Insert_Config{ + SkipStrictExistCheck: true, + }, + } + } + reqs[0].Vector.Id = a.indexId + if _, err := s.MultiInsert(ctx, &payload.Insert_MultiRequest{Requests: reqs}); err != nil { + return nil, err + } + if _, err := s.CreateIndex(ctx, &payload.Control_CreateIndexRequest{PoolSize: 100}); err != nil { + return nil, err + } + return s, nil + } + + utf8ToSjis := func(s string) string { + b, _ := ioutil.ReadAll(transform.NewReader(strings.NewReader(s), japanese.ShiftJIS.NewEncoder())) + return string(b) + } + + utf8ToEucjp := func(s string) string { + b, _ := ioutil.ReadAll(transform.NewReader(strings.NewReader(s), japanese.EUCJP.NewEncoder())) + return string(b) + } + /* Remove test cases ( focus on ID(string), only test float32 ): - Equivalence Class Testing ( 1000 vectors inserted before a search ) @@ -4679,47 +4746,215 @@ func Test_server_Remove(t *testing.T) { - NONE */ tests := []test{ - // TODO test cases - /* - { - name: "test_case_1", - args: args { - ctx: nil, - req: nil, - }, - fields: fields { - name: "", - ip: "", - ngt: nil, - eg: nil, - 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 { - name: "", - ip: "", - ngt: nil, - eg: nil, - streamConcurrency: 0, - }, - want: want{}, - checkFunc: defaultCheckFunc, - } - }(), - */ + { + name: "Equivalence Class Testing case 1.1: success exists vector", + args: args{ + ctx: ctx, + indexId: "test", + removeId: "test", + }, + want: want{ + wantUuid: "test", + }, + }, + { + name: "Equivalence Class Testing case 2.1: fail exists with non-existent ID", + args: args{ + ctx: ctx, + indexId: "test", + removeId: "non-existent", + }, + want: want{ + code: codes.NotFound, + }, + }, + { + name: "Boundary Value Testing case 1.1: fail exists with \"\"", + args: args{ + ctx: ctx, + indexId: "test", + removeId: "", + }, + want: want{ + code: codes.InvalidArgument, + }, + }, + { + name: "Boundary Value Testing case 2.1: success exists with ^@", + args: args{ + ctx: ctx, + indexId: string([]byte{0}), + removeId: string([]byte{0}), + }, + want: want{ + wantUuid: string([]byte{0}), + }, + }, + { + name: "Boundary Value Testing case 2.2: success exists with ^I", + args: args{ + ctx: ctx, + indexId: "\t", + removeId: "\t", + }, + want: want{ + wantUuid: "\t", + }, + }, + { + name: "Boundary Value Testing case 2.3: success exists with ^J", + args: args{ + ctx: ctx, + indexId: "\n", + removeId: "\n", + }, + want: want{ + wantUuid: "\n", + }, + }, + { + name: "Boundary Value Testing case 2.4: success exists with ^M", + args: args{ + ctx: ctx, + indexId: "\r", + removeId: "\r", + }, + want: want{ + wantUuid: "\r", + }, + }, + { + name: "Boundary Value Testing case 2.5: success exists with ^[", + args: args{ + ctx: ctx, + indexId: string([]byte{27}), + removeId: string([]byte{27}), + }, + want: want{ + wantUuid: string([]byte{27}), + }, + }, + { + name: "Boundary Value Testing case 2.6: success exists with ^?", + args: args{ + ctx: ctx, + indexId: string([]byte{127}), + removeId: string([]byte{127}), + }, + want: want{ + wantUuid: string([]byte{127}), + }, + }, + { + name: "Boundary Value Testing case 3.1: success exists with utf-8 ID from utf-8 index", + args: args{ + ctx: ctx, + indexId: "こんにちは", + removeId: "こんにちは", + }, + want: want{ + wantUuid: "こんにちは", + }, + }, + { + name: "Boundary Value Testing case 3.2: fail exists with utf-8 ID from s-jis index", + args: args{ + ctx: ctx, + indexId: utf8ToSjis("こんにちは"), + removeId: "こんにちは", + }, + want: want{ + code: codes.NotFound, + }, + }, + { + name: "Boundary Value Testing case 3.3: fail exists with utf-8 ID from euc-jp index", + args: args{ + ctx: ctx, + indexId: utf8ToEucjp("こんにちは"), + removeId: "こんにちは", + }, + want: want{ + code: codes.NotFound, + }, + }, + { + name: "Boundary Value Testing case 3.4: fail exists with s-jis ID from utf-8 index", + args: args{ + ctx: ctx, + indexId: "こんにちは", + removeId: utf8ToSjis("こんにちは"), + }, + want: want{ + code: codes.NotFound, + }, + }, + { + name: "Boundary Value Testing case 3.5: success exists with s-jis ID from s-jis index", + args: args{ + ctx: ctx, + indexId: utf8ToSjis("こんにちは"), + removeId: utf8ToSjis("こんにちは"), + }, + want: want{ + wantUuid: utf8ToSjis("こんにちは"), + }, + }, + { + name: "Boundary Value Testing case 3.6: fail exists with s-jis ID from euc-jp index", + args: args{ + ctx: ctx, + indexId: utf8ToEucjp("こんにちは"), + removeId: utf8ToSjis("こんにちは"), + }, + want: want{ + code: codes.NotFound, + }, + }, + { + name: "Boundary Value Testing case 3.7: fail exists with euc-jp ID from utf-8 index", + args: args{ + ctx: ctx, + indexId: "こんにちは", + removeId: utf8ToEucjp("こんにちは"), + }, + want: want{ + code: codes.NotFound, + }, + }, + { + name: "Boundary Value Testing case 3.8: fail exists with euc-jp ID from s-jis index", + args: args{ + ctx: ctx, + indexId: utf8ToSjis("こんにちは"), + removeId: utf8ToEucjp("こんにちは"), + }, + want: want{ + code: codes.NotFound, + }, + }, + { + name: "Boundary Value Testing case 3.9: success exists with euc-jp ID from euc-jp index", + args: args{ + ctx: ctx, + indexId: utf8ToEucjp("こんにちは"), + removeId: utf8ToEucjp("こんにちは"), + }, + want: want{ + wantUuid: utf8ToEucjp("こんにちは"), + }, + }, + { + name: "Boundary Value Testing case 4.1: success exists with 😀", + args: args{ + ctx: ctx, + indexId: "😀", + removeId: "😀", + }, + want: want{ + wantUuid: "😀", + }, + }, } for _, tc := range tests { @@ -4727,9 +4962,10 @@ func Test_server_Remove(t *testing.T) { t.Run(test.name, func(tt *testing.T) { tt.Parallel() defer goleak.VerifyNone(tt, goleak.IgnoreCurrent()) - if test.beforeFunc != nil { - test.beforeFunc(test.args) + if test.beforeFunc == nil { + test.beforeFunc = defaultBeforeFunc } + s, err := test.beforeFunc(test.args) if test.afterFunc != nil { defer test.afterFunc(test.args) } @@ -4737,15 +4973,13 @@ func Test_server_Remove(t *testing.T) { if test.checkFunc == nil { checkFunc = defaultCheckFunc } - s := &server{ - name: test.fields.name, - ip: test.fields.ip, - ngt: test.fields.ngt, - eg: test.fields.eg, - streamConcurrency: test.fields.streamConcurrency, - } - gotRes, err := s.Remove(test.args.ctx, test.args.req) + req := &payload.Remove_Request{ + Id: &payload.Object_ID{ + Id: test.args.removeId, + }, + } + gotRes, err := s.Remove(test.args.ctx, req) if err := checkFunc(test.want, gotRes, err); err != nil { tt.Errorf("error = %v", err) } From d93190e72276716d24be13f63e8953b0bb2cfdc7 Mon Sep 17 00:00:00 2001 From: Kosuke Morimoto Date: Wed, 11 May 2022 10:00:14 +0900 Subject: [PATCH 3/7] add error processing Signed-off-by: Kosuke Morimoto --- pkg/agent/core/ngt/handler/grpc/handler_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/agent/core/ngt/handler/grpc/handler_test.go b/pkg/agent/core/ngt/handler/grpc/handler_test.go index 94086259a3..107fc06499 100644 --- a/pkg/agent/core/ngt/handler/grpc/handler_test.go +++ b/pkg/agent/core/ngt/handler/grpc/handler_test.go @@ -4966,6 +4966,9 @@ func Test_server_Remove(t *testing.T) { test.beforeFunc = defaultBeforeFunc } s, err := test.beforeFunc(test.args) + if err != nil { + tt.Errorf("error = %v", err) + } if test.afterFunc != nil { defer test.afterFunc(test.args) } From 0c3039dde627aeb5f078f0c0dea449455667c474 Mon Sep 17 00:00:00 2001 From: Kosuke Morimoto Date: Wed, 11 May 2022 16:22:26 +0900 Subject: [PATCH 4/7] fix handler's error processing Signed-off-by: Kosuke Morimoto --- internal/errors/ngt.go | 5 + pkg/agent/core/ngt/handler/grpc/handler.go | 140 +++++++++++++++++- .../core/ngt/handler/grpc/handler_test.go | 4 +- 3 files changed, 145 insertions(+), 4 deletions(-) diff --git a/internal/errors/ngt.go b/internal/errors/ngt.go index 5a9f35ac85..c5359348e7 100644 --- a/internal/errors/ngt.go +++ b/internal/errors/ngt.go @@ -43,6 +43,11 @@ var ( return Errorf("dimension size %d is invalid, the supporting dimension size must be between 2 ~ %d", current, limit) } + // ErrInvalidUUID represents a function to generate an error that the uuid is invalid. + ErrInvalidUUID = func(uuid string) error { + return Errorf("uuid \"%s\" is invalid", uuid) + } + // ErrDimensionLimitExceed represents a function to generate an error that the supported dimension limit exceeded. ErrDimensionLimitExceed = func(current, limit int) error { return Errorf("supported dimension limit exceed:\trequired = %d,\tlimit = %d", current, limit) diff --git a/pkg/agent/core/ngt/handler/grpc/handler.go b/pkg/agent/core/ngt/handler/grpc/handler.go index 19ac913e00..595390da01 100644 --- a/pkg/agent/core/ngt/handler/grpc/handler.go +++ b/pkg/agent/core/ngt/handler/grpc/handler.go @@ -115,6 +115,28 @@ func (s *server) Exists(ctx context.Context, uid *payload.Object_ID) (res *paylo } }() uuid := uid.GetId() + if len(uuid) == 0 { + err = errors.ErrInvalidUUID(uuid) + err = status.WrapWithInvalidArgument(fmt.Sprintf("Exists API invalid argument for uuid \"%s\" detected", uuid), err, + &errdetails.RequestInfo{ + RequestId: uuid, + ServingData: errdetails.Serialize(uid), + }, + &errdetails.BadRequest{ + FieldViolations: []*errdetails.BadRequestFieldViolation{ + { + Field: "uuid", + Description: err.Error(), + }, + }, + }, + &errdetails.ResourceInfo{ + ResourceType: ngtResourceType + "/ngt.Exists", + ResourceName: fmt.Sprintf("%s: %s(%s)", apiName, s.name, s.ip), + }) + log.Warn(err) + return nil, err + } oid, ok := s.ngt.Exists(uuid) if !ok { err = errors.ErrObjectIDNotFound(uid.GetId()) @@ -267,6 +289,29 @@ func (s *server) SearchByID(ctx context.Context, req *payload.Search_IDRequest) span.End() } }() + uuid := req.GetId() + if len(uuid) == 0 { + err = errors.ErrInvalidUUID(uuid) + err = status.WrapWithInvalidArgument(fmt.Sprintf("SearchByID API invalid argument for uuid \"%s\" detected", uuid), err, + &errdetails.RequestInfo{ + RequestId: uuid, + ServingData: errdetails.Serialize(req), + }, + &errdetails.BadRequest{ + FieldViolations: []*errdetails.BadRequestFieldViolation{ + { + Field: "uuid", + Description: err.Error(), + }, + }, + }, + &errdetails.ResourceInfo{ + ResourceType: ngtResourceType + "/ngt.SearchByID", + ResourceName: fmt.Sprintf("%s: %s(%s)", apiName, s.name, s.ip), + }) + log.Warn(err) + return nil, err + } vec, dst, err := s.ngt.SearchByID( req.GetId(), req.GetConfig().GetNum(), @@ -747,8 +792,31 @@ func (s *server) LinearSearchByID(ctx context.Context, req *payload.Search_IDReq span.End() } }() + uuid := req.GetId() + if len(uuid) == 0 { + err = errors.ErrInvalidUUID(uuid) + err = status.WrapWithInvalidArgument(fmt.Sprintf("LinearSearchByID API invalid argument for uuid \"%s\" detected", uuid), err, + &errdetails.RequestInfo{ + RequestId: uuid, + ServingData: errdetails.Serialize(req), + }, + &errdetails.BadRequest{ + FieldViolations: []*errdetails.BadRequestFieldViolation{ + { + Field: "uuid", + Description: err.Error(), + }, + }, + }, + &errdetails.ResourceInfo{ + ResourceType: ngtResourceType + "/ngt.LinearSearchByID", + ResourceName: fmt.Sprintf("%s: %s(%s)", apiName, s.name, s.ip), + }) + log.Warn(err) + return nil, err + } vec, dst, err := s.ngt.LinearSearchByID( - req.GetId(), + uuid, req.GetConfig().GetNum()) res, err = toSearchResponse(dst, err) if err != nil || res == nil { @@ -1361,7 +1429,30 @@ func (s *server) Update(ctx context.Context, req *payload.Update_Request) (res * } return nil, err } - err = s.ngt.UpdateWithTime(vec.GetId(), vec.GetVector(), req.GetConfig().GetTimestamp()) + uuid := vec.GetId() + if len(uuid) == 0 { + err = errors.ErrInvalidUUID(uuid) + err = status.WrapWithInvalidArgument(fmt.Sprintf("Update API invalid argument for uuid \"%s\" detected", uuid), err, + &errdetails.RequestInfo{ + RequestId: uuid, + ServingData: errdetails.Serialize(req), + }, + &errdetails.BadRequest{ + FieldViolations: []*errdetails.BadRequestFieldViolation{ + { + Field: "uuid", + Description: err.Error(), + }, + }, + }, + &errdetails.ResourceInfo{ + ResourceType: ngtResourceType + "/ngt.Update", + ResourceName: fmt.Sprintf("%s: %s(%s)", apiName, s.name, s.ip), + }) + log.Warn(err) + return nil, err + } + err = s.ngt.UpdateWithTime(uuid, vec.GetVector(), req.GetConfig().GetTimestamp()) if err != nil { var code trace.Status if errors.Is(err, errors.ErrObjectIDNotFound(vec.GetId())) { @@ -1643,6 +1734,29 @@ func (s *server) Upsert(ctx context.Context, req *payload.Upsert_Request) (loc * } return nil, err } + uuid := vec.GetId() + if len(uuid) == 0 { + err = errors.ErrInvalidUUID(uuid) + err = status.WrapWithInvalidArgument(fmt.Sprintf("Upsert API invalid argument for uuid \"%s\" detected", uuid), err, + &errdetails.RequestInfo{ + RequestId: uuid, + ServingData: errdetails.Serialize(req), + }, + &errdetails.BadRequest{ + FieldViolations: []*errdetails.BadRequestFieldViolation{ + { + Field: "uuid", + Description: err.Error(), + }, + }, + }, + &errdetails.ResourceInfo{ + ResourceType: ngtResourceType + "/ngt.Upsert", + ResourceName: fmt.Sprintf("%s: %s(%s)", apiName, s.name, s.ip), + }) + log.Warn(err) + return nil, err + } rtName := "/ngt.Upsert" _, exists := s.ngt.Exists(req.GetVector().GetId()) @@ -1888,6 +2002,28 @@ func (s *server) Remove(ctx context.Context, req *payload.Remove_Request) (res * }() id := req.GetId() uuid := id.GetId() + if len(uuid) == 0 { + err = errors.ErrInvalidUUID(uuid) + err = status.WrapWithInvalidArgument(fmt.Sprintf("Remove API invalid argument for uuid \"%s\" detected", uuid), err, + &errdetails.RequestInfo{ + RequestId: uuid, + ServingData: errdetails.Serialize(req), + }, + &errdetails.BadRequest{ + FieldViolations: []*errdetails.BadRequestFieldViolation{ + { + Field: "uuid", + Description: err.Error(), + }, + }, + }, + &errdetails.ResourceInfo{ + ResourceType: ngtResourceType + "/ngt.Remove", + ResourceName: fmt.Sprintf("%s: %s(%s)", apiName, s.name, s.ip), + }) + log.Warn(err) + return nil, err + } err = s.ngt.DeleteWithTime(uuid, req.GetConfig().GetTimestamp()) if err != nil { var code trace.Status diff --git a/pkg/agent/core/ngt/handler/grpc/handler_test.go b/pkg/agent/core/ngt/handler/grpc/handler_test.go index 107fc06499..9b6862a096 100644 --- a/pkg/agent/core/ngt/handler/grpc/handler_test.go +++ b/pkg/agent/core/ngt/handler/grpc/handler_test.go @@ -481,7 +481,7 @@ func Test_server_Exists(t *testing.T) { searchId: "", }, want: want{ - code: codes.NotFound, + code: codes.InvalidArgument, }, }, { @@ -1680,7 +1680,7 @@ func Test_server_SearchByID(t *testing.T) { }, want: want{ resultSize: 0, - code: codes.NotFound, + code: codes.InvalidArgument, }, }, { From 6fac27ffd79e04f6c684bf7cae26bc9a311e7092 Mon Sep 17 00:00:00 2001 From: Kosuke Morimoto Date: Wed, 11 May 2022 16:25:05 +0900 Subject: [PATCH 5/7] fix handler's error processing to GetObject Signed-off-by: Kosuke Morimoto --- pkg/agent/core/ngt/handler/grpc/handler.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pkg/agent/core/ngt/handler/grpc/handler.go b/pkg/agent/core/ngt/handler/grpc/handler.go index 595390da01..4d088e2670 100644 --- a/pkg/agent/core/ngt/handler/grpc/handler.go +++ b/pkg/agent/core/ngt/handler/grpc/handler.go @@ -2209,6 +2209,28 @@ func (s *server) GetObject(ctx context.Context, id *payload.Object_VectorRequest } }() uuid := id.GetId().GetId() + if len(uuid) == 0 { + err = errors.ErrInvalidUUID(uuid) + err = status.WrapWithInvalidArgument(fmt.Sprintf("GetObject API invalid argument for uuid \"%s\" detected", uuid), err, + &errdetails.RequestInfo{ + RequestId: uuid, + ServingData: errdetails.Serialize(id), + }, + &errdetails.BadRequest{ + FieldViolations: []*errdetails.BadRequestFieldViolation{ + { + Field: "uuid", + Description: err.Error(), + }, + }, + }, + &errdetails.ResourceInfo{ + ResourceType: ngtResourceType + "/ngt.GetObject", + ResourceName: fmt.Sprintf("%s: %s(%s)", apiName, s.name, s.ip), + }) + log.Warn(err) + return nil, err + } vec, err := s.ngt.GetObject(uuid) if err != nil || vec == nil { err = errors.ErrObjectNotFound(err, uuid) From 3989d374cf31293ed6b0d0b4689b9ec4e89e943e Mon Sep 17 00:00:00 2001 From: Kosuke Morimoto Date: Wed, 11 May 2022 18:15:54 +0900 Subject: [PATCH 6/7] add ErrInvalidUUID test case Signed-off-by: Kosuke Morimoto --- internal/errors/ngt_test.go | 63 +++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/internal/errors/ngt_test.go b/internal/errors/ngt_test.go index 385b50ed5b..48e0d0d4a4 100644 --- a/internal/errors/ngt_test.go +++ b/internal/errors/ngt_test.go @@ -288,6 +288,69 @@ func TestErrInvalidDimensionSize(t *testing.T) { } } +func TestErrInvalidUUID(t *testing.T) { + type args struct { + uuid string + } + type want struct { + want error + } + type test struct { + name string + args args + want want + checkFunc func(want, error) error + beforeFunc func(args) + afterFunc func(args) + } + defaultCheckFunc := func(w want, got error) error { + if !Is(got, w.want) { + return Errorf("got: \"%#v\",\n\t\t\t\twant: \"%#v\"", got, w.want) + } + return nil + } + tests := []test{ + { + name: "return an ErrInvalidUUID error when uuid is empty string", + args: args{ + uuid: "", + }, + want: want{ + want: New("uuid \"\" is invalid"), + }, + }, + { + name: "return an ErrInvalidUUID error when uuid is foo", + args: args{ + uuid: "foo", + }, + want: want{ + want: New("uuid \"foo\" is invalid"), + }, + }, + } + + 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) + } + checkFunc := test.checkFunc + if test.checkFunc == nil { + checkFunc = defaultCheckFunc + } + + got := ErrInvalidUUID(test.args.uuid) + if err := checkFunc(test.want, got); err != nil { + tt.Errorf("error = %v", err) + } + }) + } +} + func TestErrDimensionLimitExceed(t *testing.T) { type args struct { current int From 9eeb9d2891abd0bd8df8ee780eaf5c720468b1f1 Mon Sep 17 00:00:00 2001 From: Kosuke Morimoto Date: Wed, 11 May 2022 18:24:33 +0900 Subject: [PATCH 7/7] Update pkg/agent/core/ngt/handler/grpc/handler.go Co-authored-by: Yusuke Kato --- pkg/agent/core/ngt/handler/grpc/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/agent/core/ngt/handler/grpc/handler.go b/pkg/agent/core/ngt/handler/grpc/handler.go index 4d088e2670..5e9e0f4024 100644 --- a/pkg/agent/core/ngt/handler/grpc/handler.go +++ b/pkg/agent/core/ngt/handler/grpc/handler.go @@ -313,7 +313,7 @@ func (s *server) SearchByID(ctx context.Context, req *payload.Search_IDRequest) return nil, err } vec, dst, err := s.ngt.SearchByID( - req.GetId(), + uuid, req.GetConfig().GetNum(), req.GetConfig().GetEpsilon(), req.GetConfig().GetRadius())