Repository: milvus-io/milvus-sdk-go
Pull request #340 (2022-11-17 09:02:03)

Merge index name option to simplify client
See also #339

/kind improvement

Signed-off-by: Congqi Xia <congqi.xia@zilliz.com>

sre-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/340#" title="Author self-approved">congqixia</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=milvus-io%2Fmilvus-sdk-go).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/milvus-io/milvus-sdk-go/blob/master/OWNERS)~~ [congqixia]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/milvus-io/milvus-sdk-go/pull/340?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) Report
> Merging [#340](https://codecov.io/gh/milvus-io/milvus-sdk-go/pull/340?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) (0b311cd) into [master](https://codecov.io/gh/milvus-io/milvus-sdk-go/commit/7e7e3f8c4d94fdf73e3a0c66d058c7dd308b0f4c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) (7e7e3f8) will **increase** coverage by `0.68%`.
> The diff coverage is `89.47%`.

[![Impacted file tree graph](https://codecov.io/gh/milvus-io/milvus-sdk-go/pull/340/graphs/tree.svg?width=650&height=150&src=pr&token=WJK43PV390&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io)](https://codecov.io/gh/milvus-io/milvus-sdk-go/pull/340?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io)

```diff
@@            Coverage Diff             @@
##           master     #340      +/-   ##
==========================================
+ Coverage   83.97%   84.65%   +0.68%     
==========================================
  Files          29       27       -2     
  Lines        3251     3148     -103     
==========================================
- Hits         2730     2665      -65     
+ Misses        419      387      -32     
+ Partials      102       96       -6     
```


| [Impacted Files](https://codecov.io/gh/milvus-io/milvus-sdk-go/pull/340?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io) | Coverage Δ | |
|---|---|---|
| [client/client.go](https://codecov.io/gh/milvus-io/milvus-sdk-go/pull/340/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io#diff-Y2xpZW50L2NsaWVudC5nbw==) | `75.80% <ø> (ø)` | |
| [client/client\_grpc\_index.go](https://codecov.io/gh/milvus-io/milvus-sdk-go/pull/340/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=milvus-io#diff-Y2xpZW50L2NsaWVudF9ncnBjX2luZGV4Lmdv) | `83.73% <89.47%> (+0.10%)` | :arrow_up: |

ThreadDao: /lgtm

Patch:
diff --git a/client/client.go b/client/client.go
index 6305778..836fe64 100644
--- a/client/client.go
+++ b/client/client.go
@@ -97,15 +97,15 @@ type Client interface {
 
 	// CreateIndex create index for field of specified collection
 	// currently index naming is not supported, so only one index on vector field is supported
-	CreateIndex(ctx context.Context, collName string, fieldName string, idx entity.Index, async bool) error
+	CreateIndex(ctx context.Context, collName string, fieldName string, idx entity.Index, async bool, opts ...IndexOption) error
 	// DescribeIndex describe index on collection
 	// currently index naming is not supported, so only one index on vector field is supported
-	DescribeIndex(ctx context.Context, collName string, fieldName string) ([]entity.Index, error)
+	DescribeIndex(ctx context.Context, collName string, fieldName string, opts ...IndexOption) ([]entity.Index, error)
 	// DropIndex drop index from collection with specified field name
-	DropIndex(ctx context.Context, collName string, fieldName string) error
+	DropIndex(ctx context.Context, collName string, fieldName string, opts ...IndexOption) error
 	// GetIndexState get index state with specified collection and field name
 	// index naming is not supported yet
-	GetIndexState(ctx context.Context, collName string, fieldName string) (entity.IndexState, error)
+	GetIndexState(ctx context.Context, collName string, fieldName string, opts ...IndexOption) (entity.IndexState, error)
 
 	// -- basic operation --
 
diff --git a/client/client_grpc_index.go b/client/client_grpc_index.go
index 15ec57c..fea0c14 100644
--- a/client/client_grpc_index.go
+++ b/client/client_grpc_index.go
@@ -46,10 +46,35 @@ func (c *GrpcClient) checkCollField(ctx context.Context, collName string, fieldN
 	return nil
 }
 
+type indexDef struct {
+	name           string
+	fieldName      string
+	collectionName string
+}
+
+// IndexOption is the predefined function to alter index def.
+// shared among create, describe, drop indexes operations.
+type IndexOption func(*indexDef)
+
+// WithIndexName returns an IndexOption with customized index name.
+func WithIndexName(name string) IndexOption {
+	return func(def *indexDef) {
+		def.name = name
+	}
+}
+
+func getIndexDef(opts ...IndexOption) indexDef {
+	idxDef := indexDef{}
+	for _, opt := range opts {
+		opt(&idxDef)
+	}
+	return idxDef
+}
+
 // CreateIndex create index for collection
 // Deprecated please use CreateIndexV2 instead.
 func (c *GrpcClient) CreateIndex(ctx context.Context, collName string, fieldName string,
-	idx entity.Index, async bool) error {
+	idx entity.Index, async bool, opts ...IndexOption) error {
 	if c.Service == nil {
 		return ErrClientNotReady
 	}
@@ -62,12 +87,16 @@ func (c *GrpcClient) CreateIndex(ctx context.Context, collName string, fieldName
 		return flushErr
 	}
 
+	idxDef := getIndexDef(opts...)
+
 	req := &server.CreateIndexRequest{
 		DbName:         "", // reserved
 		CollectionName: collName,
 		FieldName:      fieldName,
+		IndexName:      idxDef.name,
 		ExtraParams:    entity.MapKvPairs(idx.Params()),
 	}
+
 	resp, err := c.Service.CreateIndex(ctx, req)
 	if err != nil {
 		return err
@@ -77,7 +106,7 @@ func (c *GrpcClient) CreateIndex(ctx context.Context, collName string, fieldName
 	}
 	if !async { // sync mode, wait index building result
 		for {
-			is, err := c.GetIndexState(ctx, collName, fieldName)
+			is, err := c.GetIndexState(ctx, collName, fieldName, opts...)
 			if err != nil {
 				return err
 			}
@@ -96,18 +125,21 @@ func (c *GrpcClient) CreateIndex(ctx context.Context, collName string, fieldName
 
 // DescribeIndex describe index
 // Deprecate please use DescribeIndexV2 instead.
-func (c *GrpcClient) DescribeIndex(ctx context.Context, collName string, fieldName string) ([]entity.Index, error) {
+func (c *GrpcClient) DescribeIndex(ctx context.Context, collName string, fieldName string, opts ...IndexOption) ([]entity.Index, error) {
 	if c.Service == nil {
 		return []entity.Index{}, ErrClientNotReady
 	}
 	if err := c.checkCollField(ctx, collName, fieldName); err != nil {
 		return []entity.Index{}, err
 	}
+
+	idxDef := getIndexDef(opts...)
 	req := &server.DescribeIndexRequest{
 		CollectionName: collName,
 		FieldName:      fieldName,
-		IndexName:      "", // empty string stands for all index on collection
+		IndexName:      idxDef.name,
 	}
+
 	resp, err := c.Service.DescribeIndex(ctx, req)
 	if err != nil {
 		return []entity.Index{}, err
@@ -131,19 +163,25 @@ func (c *GrpcClient) DescribeIndex(ctx context.Context, collName string, fieldNa
 
 // DropIndex drop index from collection
 // Deprecate please use DropIndexV2 instead.
-func (c *GrpcClient) DropIndex(ctx context.Context, collName string, fieldName string) error {
+func (c *GrpcClient) DropIndex(ctx context.Context, collName string, fieldName string, opts ...IndexOption) error {
 	if c.Service == nil {
 		return ErrClientNotReady
 	}
 	if err := c.checkCollField(ctx, collName, fieldName); err != nil {
 		return err
 	}
+
+	idxDef := getIndexDef(opts...)
 	req := &server.DropIndexRequest{
 		DbName:         "", //reserved,
 		CollectionName: collName,
 		FieldName:      fieldName,
-		IndexName:      "", //reserved
+		IndexName:      idxDef.name,
 	}
+	if idxDef.name != "" {
+		req.IndexName = idxDef.name
+	}
+
 	resp, err := c.Service.DropIndex(ctx, req)
 	if err != nil {
 		return err
@@ -153,18 +191,20 @@ func (c *GrpcClient) DropIndex(ctx context.Context, collName string, fieldName s
 
 // GetIndexState get index state
 // Deprecate please use DescribeIndexV2 instead.
-func (c *GrpcClient) GetIndexState(ctx context.Context, collName string, fieldName string) (entity.IndexState, error) {
+func (c *GrpcClient) GetIndexState(ctx context.Context, collName string, fieldName string, opts ...IndexOption) (entity.IndexState, error) {
 	if c.Service == nil {
 		return entity.IndexState(common.IndexState_Failed), ErrClientNotReady
 	}
 	if err := c.checkCollField(ctx, collName, fieldName); err != nil {
 		return entity.IndexState(common.IndexState_IndexStateNone), err
 	}
+
+	idxDef := getIndexDef(opts...)
 	req := &server.GetIndexStateRequest{
 		DbName:         "",
 		CollectionName: collName,
 		FieldName:      fieldName,
-		IndexName:      "",
+		IndexName:      idxDef.name,
 	}
 	resp, err := c.Service.GetIndexState(ctx, req)
 	if err != nil {
@@ -179,18 +219,20 @@ func (c *GrpcClient) GetIndexState(ctx context.Context, collName string, fieldNa
 
 // GetIndexBuildProgress get index building progress
 // Deprecate please use DescribeIndexV2 instead.
-func (c *GrpcClient) GetIndexBuildProgress(ctx context.Context, collName string, fieldName string) (total, indexed int64, err error) {
+func (c *GrpcClient) GetIndexBuildProgress(ctx context.Context, collName string, fieldName string, opts ...IndexOption) (total, indexed int64, err error) {
 	if c.Service == nil {
 		return 0, 0, ErrClientNotReady
 	}
 	if err := c.checkCollField(ctx, collName, fieldName); err != nil {
 		return 0, 0, err
 	}
+
+	idxDef := getIndexDef(opts...)
 	req := &server.GetIndexBuildProgressRequest{
 		DbName:         "",
 		CollectionName: collName,
 		FieldName:      fieldName,
-		IndexName:      "",
+		IndexName:      idxDef.name,
 	}
 	resp, err := c.Service.GetIndexBuildProgress(ctx, req)
 	if err != nil {
diff --git a/client/v2/client.go b/client/v2/client.go
deleted file mode 100644
index e69e792..0000000
--- a/client/v2/client.go
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright (C) 2019-2021 Zilliz. All rights reserved.
-//
-// 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
-//
-// http://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 v2
-
-import (
-	"context"
-	"fmt"
-	"math"
-	"time"
-
-	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
-	grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/credentials/insecure"
-
-	server "github.com/milvus-io/milvus-proto/go-api/milvuspb"
-	"github.com/milvus-io/milvus-sdk-go/v2/client"
-	"github.com/milvus-io/milvus-sdk-go/v2/entity"
-	"google.golang.org/grpc"
-)
-
-// Client is the interface used to communicate with Milvus
-type Client interface {
-	// Close the remaining connection resources
-	Close() error
-
-	// -- collection --
-
-	// ListCollections list collections from connection
-	ListCollections(ctx context.Context) ([]*entity.Collection, error)
-	// CreateCollection create collection using provided schema
-	CreateCollection(ctx context.Context, schema *entity.Schema, shardsNum int32, opts ...client.CreateCollectionOption) error
-	// DescribeCollection describe collection meta
-	DescribeCollection(ctx context.Context, collName string) (*entity.Collection, error)
-	// DropCollection drop the specified collection
-	DropCollection(ctx context.Context, collName string) error
-	// GetCollectionStatistics get collection statistics
-	GetCollectionStatistics(ctx context.Context, collName string) (map[string]string, error)
-	// LoadCollection load collection into memory
-	LoadCollection(ctx context.Context, collName string, async bool, opts ...client.LoadCollectionOption) error
-	// ReleaseCollection release loaded collection
-	ReleaseCollection(ctx context.Context, collName string) error
-	// HasCollection check whether collection exists
-	HasCollection(ctx context.Context, collName string) (bool, error)
-
-	// CreateAlias creates an alias for collection
-	CreateAlias(ctx context.Context, collName string, alias string) error
-	// DropAlias drops the specified Alias
-	DropAlias(ctx context.Context, alias string) error
-	// AlterAlias changes collection alias to provided alias
-	AlterAlias(ctx context.Context, collName string, alias string) error
-
-	// GetReplicas gets the replica groups as well as their querynodes and shards information
-	GetReplicas(ctx context.Context, collName string) ([]*entity.ReplicaGroup, error)
-
-	// -- authentication --
-
-	// CreateCredential create new user and password
-	CreateCredential(ctx context.Context, username string, password string) error
-	// UpdateCredential update password for a user
-	UpdateCredential(ctx context.Context, username string, oldPassword string, newPassword string) error
-	// DeleteCredential delete a user
-	DeleteCredential(ctx context.Context, username string) error
-	// ListCredUsers list all usernames
-	ListCredUsers(ctx context.Context) ([]string, error)
-
-	// -- partition --
-
-	// CreatePartition create partition for collection
-	CreatePartition(ctx context.Context, collName string, partitionName string) error
-	// DropPartition drop partition from collection
-	DropPartition(ctx context.Context, collName string, partitionName string) error
-	// ShowPartitions list all partitions from collection
-	ShowPartitions(ctx context.Context, collName string) ([]*entity.Partition, error)
-	// HasPartition check whether partition exists in collection
-	HasPartition(ctx context.Context, collName string, partitionName string) (bool, error)
-	// LoadPartitions load partitions into memory
-	LoadPartitions(ctx context.Context, collName string, partitionNames []string, async bool) error
-	// ReleasePartitions release partitions
-	ReleasePartitions(ctx context.Context, collName string, partitionNames []string) error
-
-	// -- segment --
-	GetPersistentSegmentInfo(ctx context.Context, collName string) ([]*entity.Segment, error)
-	// -- index --
-
-	// CreateIndex create index for field of specified collection
-	// currently index naming is not supported, so only one index on vector field is supported
-	CreateIndex(ctx context.Context, async bool, idx entity.Index, opts ...CreateIndexRequestOption) error
-	// DescribeIndex describe index on collection
-	// currently index naming is not supported, so only one index on vector field is supported
-	DescribeIndex(ctx context.Context, opts ...DescribeIndexRequestOption) ([]*server.IndexDescription, error)
-	// DropIndex drop index from collection with specified field name
-	DropIndex(ctx context.Context, opts ...DropIndexOption) error
-	// GetIndexState get index state with specified collection and field name
-	// index naming is not supported yet
-	// Deprecated use DescribeIndexV2 instead.
-	GetIndexState(ctx context.Context, collName string, fieldName string) (entity.IndexState, error)
-
-	// -- basic operation --
-
-	// Insert column-based data into collection, returns id column values
-	Insert(ctx context.Context, collName string, partitionName string, columns ...entity.Column) (entity.Column, error)
-	// Flush flush collection, specified
-	Flush(ctx context.Context, collName string, async bool) error
-	// DeleteByPks deletes entries related to provided primary keys
-	DeleteByPks(ctx context.Context, collName string, partitionName string, ids entity.Column) error
-	// Search search with bool expression
-	Search(ctx context.Context, collName string, partitions []string,
-		expr string, outputFields []string, vectors []entity.Vector, vectorField string, metricType entity.MetricType, topK int, sp entity.SearchParam, opts ...client.SearchQueryOptionFunc) ([]client.SearchResult, error)
-	// QueryByPks query record by specified primary key(s)
-	QueryByPks(ctx context.Context, collectionName string, partitionNames []string, ids entity.Column, outputFields []string, opts ...client.SearchQueryOptionFunc) ([]entity.Column, error)
-
-	// CalcDistance calculate the distance between vectors specified by ids or provided
-	CalcDistance(ctx context.Context, collName string, partitions []string,
-		metricType entity.MetricType, opLeft, opRight entity.Column) (entity.Column, error)
-
-	// -- row based apis --
-
-	// CreateCollectionByRow create collection by row
-	CreateCollectionByRow(ctx context.Context, row entity.Row, shardNum int32) error
-	// InsertByRows insert by rows
-	InsertByRows(ctx context.Context, collName string, paritionName string, rows []entity.Row) (entity.Column, error)
-
-	// ManualCompaction triggers a compaction on provided collection
-	ManualCompaction(ctx context.Context, collName string, toleranceDuration time.Duration) (int64, error)
-	// GetCompactionState get compaction state of provided compaction id
-	GetCompactionState(ctx context.Context, id int64) (entity.CompactionState, error)
-	// GetCompactionStateWithPlans get compaction state with plans of provided compaction id
-	GetCompactionStateWithPlans(ctx context.Context, id int64) (entity.CompactionState, []entity.CompactionPlan, error)
-
-	// BulkInsert import data files(json, numpy, etc.) on MinIO/S3 storage, read and parse them into sealed segments
-	BulkInsert(ctx context.Context, collName string, partitionName string, rowBased bool, files []string, opts ...client.BulkInsertOption) ([]int64, error)
-	// GetBulkInsertState checks import task state
-	GetBulkInsertState(ctx context.Context, taskID int64) (*entity.BulkInsertTaskState, error)
-	// ListBulkInsertTasks list state of all import tasks
-	ListBulkInsertTasks(ctx context.Context, collName string, limit int64) ([]*entity.BulkInsertTaskState, error)
-}
-
-// grpcClient, uses default grpc service definition to connect with Milvus2.0
-type grpcClient struct {
-	client.GrpcClient
-	//conn    *grpc.ClientConn           // grpc connection instance
-	//service server.MilvusServiceClient // service client stub
-}
-
-// connect connect to service
-func (c *grpcClient) connect(ctx context.Context, addr string, opts ...grpc.DialOption) error {
-	if addr == "" {
-		return fmt.Errorf("address is empty")
-	}
-	conn, err := grpc.Dial(addr, opts...)
-	if err != nil {
-		return err
-	}
-
-	c.Conn = conn
-	c.Service = server.NewMilvusServiceClient(c.Conn)
-	return nil
-}
-
-// Close the connection
-func (c *grpcClient) Close() error {
-	if c.Conn != nil {
-		err := c.Conn.Close()
-		c.Conn = nil
-		return err
-	}
-	return nil
-}
-
-// NewGrpcClient create client with grpc addr
-// the `Connect` API will be called for you
-// dialOptions contains the dial option(s) that control the grpc dialing process
-func NewGrpcClient(ctx context.Context, addr string, dialOptions ...grpc.DialOption) (Client, error) {
-	c := &grpcClient{}
-	if len(dialOptions) == 0 {
-		return NewDefaultGrpcClient(ctx, addr)
-	}
-
-	if err := c.connect(ctx, addr, dialOptions...); err != nil {
-		return nil, err
-	}
-
-	return c, nil
-}
-
-func NewDefaultGrpcClient(ctx context.Context, addr string) (Client, error) {
-	c := &grpcClient{}
-	defaultOpts := append(client.DefaultGrpcOpts,
-		grpc.WithTransportCredentials(insecure.NewCredentials()),
-		grpc.WithUnaryInterceptor(
-			grpc_middleware.ChainUnaryClient(
-				grpc_retry.UnaryClientInterceptor(
-					grpc_retry.WithMax(6),
-					grpc_retry.WithBackoff(func(attempt uint) time.Duration {
-						return 60 * time.Millisecond * time.Duration(math.Pow(3, float64(attempt)))
-					}),
-					grpc_retry.WithCodes(codes.Unavailable, codes.ResourceExhausted)),
-				client.RetryOnRateLimitInterceptor(10, func(ctx context.Context, attempt uint) time.Duration {
-					return 10 * time.Millisecond * time.Duration(math.Pow(3, float64(attempt)))
-				}),
-			),
-		),
-	)
-	err := c.connect(ctx, addr, defaultOpts...)
-	if err != nil {
-		return nil, err
-	}
-	return c, nil
-}
diff --git a/client/v2/client_grpc_index.go b/client/v2/client_grpc_index.go
deleted file mode 100644
index 4cc4fb3..0000000
--- a/client/v2/client_grpc_index.go
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright (C) 2019-2021 Zilliz. All rights reserved.
-//
-// 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
-//
-// http://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 v2
-
-import (
-	"context"
-	"errors"
-	"time"
-
-	common "github.com/milvus-io/milvus-proto/go-api/commonpb"
-	server "github.com/milvus-io/milvus-proto/go-api/milvuspb"
-	"github.com/milvus-io/milvus-sdk-go/v2/client"
-	"github.com/milvus-io/milvus-sdk-go/v2/entity"
-)
-
-// handles response status
-// if status is nil returns ErrStatusNil
-// if status.ErrorCode is common.ErrorCode_Success, returns nil
-// otherwise, try use Reason into ErrServiceFailed
-// if Reason is empty, returns ErrServiceFailed with default string
-func handleRespStatus(status *common.Status) error {
-	if status == nil {
-		return client.ErrStatusNil
-	}
-	if status.ErrorCode != common.ErrorCode_Success {
-		if status.GetReason() != "" {
-			return client.ErrServiceFailed(errors.New(status.GetReason()))
-		}
-		return client.ErrServiceFailed(errors.New("service failed"))
-	}
-	return nil
-}
-
-type CreateIndexRequestOption func(req *server.CreateIndexRequest)
-
-func SetCollectionNameForCreateIndex(name string) CreateIndexRequestOption {
-	return func(req *server.CreateIndexRequest) {
-		req.CollectionName = name
-	}
-}
-
-func SetIndexNameForCreateIndex(name string) CreateIndexRequestOption {
-	return func(req *server.CreateIndexRequest) {
-		req.IndexName = name
-	}
-}
-
-func SetFieldNameForCreateIndex(name string) CreateIndexRequestOption {
-	return func(req *server.CreateIndexRequest) {
-		req.FieldName = name
-	}
-}
-
-// CreateIndex create index for collection
-func (c *grpcClient) CreateIndex(ctx context.Context, async bool, idx entity.Index, opts ...CreateIndexRequestOption) error {
-	if c.Service == nil {
-		return client.ErrClientNotReady
-	}
-	req := &server.CreateIndexRequest{
-		ExtraParams: entity.MapKvPairs(idx.Params()),
-	}
-	for _, opt := range opts {
-		opt(req)
-	}
-	if req.GetCollectionName() == "" {
-		return errors.New("collection name can not be empty")
-	}
-	if req.GetFieldName() == "" {
-		return errors.New("field name can not be empty")
-	}
-
-	resp, err := c.Service.CreateIndex(ctx, req)
-	if err != nil {
-		return err
-	}
-	if err = handleRespStatus(resp); err != nil {
-		return err
-	}
-	if !async { // sync mode, wait index building result
-		for {
-			resp, err := c.Service.DescribeIndex(ctx, &server.DescribeIndexRequest{
-				DbName:         "",
-				CollectionName: req.GetCollectionName(),
-				FieldName:      req.GetFieldName(),
-				IndexName:      req.GetIndexName(),
-			})
-			if err != nil {
-				return err
-			}
-			if err = handleRespStatus(resp.Status); err != nil {
-				return err
-			}
-			for _, index := range resp.GetIndexDescriptions() {
-				if (req.GetIndexName() == "" && index.FieldName == req.GetFieldName()) || req.GetIndexName() == index.GetIndexName() {
-					switch index.GetState() {
-					case common.IndexState_Failed:
-						return errors.New("index build failed")
-					case common.IndexState_Finished:
-						return nil
-					default:
-					}
-				}
-			}
-			time.Sleep(100 * time.Millisecond) // wait 100ms
-		}
-	}
-	return nil
-}
-
-type DescribeIndexRequestOption func(req *server.DescribeIndexRequest)
-
-func SetCollectionNameForDescribeIndex(name string) DescribeIndexRequestOption {
-	return func(req *server.DescribeIndexRequest) {
-		req.CollectionName = name
-	}
-}
-
-func SetIndexNameForDescribeIndex(name string) DescribeIndexRequestOption {
-	return func(req *server.DescribeIndexRequest) {
-		req.IndexName = name
-	}
-}
-
-func SetFieldNameForDescribeIndex(name string) DescribeIndexRequestOption {
-	return func(req *server.DescribeIndexRequest) {
-		req.FieldName = name
-	}
-}
-
-// DescribeIndex describe index
-func (c *grpcClient) DescribeIndex(ctx context.Context, opts ...DescribeIndexRequestOption) ([]*server.IndexDescription, error) {
-	if c.Service == nil {
-		return []*server.IndexDescription{}, client.ErrClientNotReady
-	}
-
-	req := &server.DescribeIndexRequest{}
-	for _, opt := range opts {
-		opt(req)
-	}
-	if req.GetCollectionName() == "" {
-		return []*server.IndexDescription{}, errors.New("collection name can not be empty")
-	}
-	resp, err := c.Service.DescribeIndex(ctx, req)
-	if err != nil {
-		return []*server.IndexDescription{}, err
-	}
-	if err := handleRespStatus(resp.GetStatus()); err != nil {
-		return []*server.IndexDescription{}, err
-	}
-	return resp.GetIndexDescriptions(), nil
-}
-
-type DropIndexOption func(request *server.DropIndexRequest)
-
-func SetCollectionNameForDropIndex(name string) DropIndexOption {
-	return func(req *server.DropIndexRequest) {
-		req.CollectionName = name
-	}
-}
-func SetIndexNameForDropIndex(name string) DropIndexOption {
-	return func(req *server.DropIndexRequest) {
-		req.IndexName = name
-	}
-}
-
-func SetFieldNameForDroIndex(name string) DropIndexOption {
-	return func(req *server.DropIndexRequest) {
-		req.FieldName = name
-	}
-}
-
-// DropIndex drop index from collection
-func (c *grpcClient) DropIndex(ctx context.Context, opts ...DropIndexOption) error {
-	if c.Service == nil {
-		return client.ErrClientNotReady
-	}
-	req := &server.DropIndexRequest{}
-	for _, opt := range opts {
-		opt(req)
-	}
-	if req.GetCollectionName() == "" {
-		return errors.New("collection name can not be empty")
-	}
-
-	resp, err := c.Service.DropIndex(ctx, req)
-	if err != nil {
-		return err
-	}
-	return handleRespStatus(resp)
-}
diff --git a/examples/index/index_v2/index_v2.go b/examples/index/index_v2/index_v2.go
deleted file mode 100644
index 760ce43..0000000
--- a/examples/index/index_v2/index_v2.go
+++ /dev/null
@@ -1,302 +0,0 @@
-package main
-
-import (
-	"context"
-	"encoding/csv"
-	"fmt"
-	"log"
-	"os"
-	"strconv"
-	"strings"
-	"time"
-
-	v2 "github.com/milvus-io/milvus-sdk-go/v2/client/v2"
-	"github.com/milvus-io/milvus-sdk-go/v2/entity"
-)
-
-func main() {
-	// Milvus instance proxy address, may verify in your env/settings
-	milvusAddr := "localhost:19530"
-
-	// setup context for client creation, use 2 seconds here
-	ctx := context.Background()
-	ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
-	defer cancel()
-
-	c, err := v2.NewGrpcClient(ctx, milvusAddr)
-	if err != nil {
-		// handling error and exit, to make example simple here
-		log.Fatal("failed to connect to milvus:", err.Error())
-	}
-	// in a main func, remember to close the client
-	defer c.Close()
-
-	// here is the collection name we use in this example
-	collectionName := `gosdk_index_v2_example`
-
-	has, err := c.HasCollection(ctx, collectionName)
-	if err != nil {
-		log.Fatal("failed to check whether collection exists:", err.Error())
-	}
-	if has {
-		// collection with same name exist, clean up mess
-		_ = c.DropCollection(ctx, collectionName)
-	}
-
-	// define collection schema, see film.csv
-	schema := &entity.Schema{
-		CollectionName: collectionName,
-		Description:    "this is the example collection for inser and search",
-		AutoID:         false,
-		Fields: []*entity.Field{
-			{
-				Name:       "ID",
-				DataType:   entity.FieldTypeInt64, // int64 only for now
-				PrimaryKey: true,
-				AutoID:     false,
-			},
-			{
-				Name:       "Year",
-				DataType:   entity.FieldTypeInt32,
-				PrimaryKey: false,
-				AutoID:     false,
-			},
-			{
-				Name:     "Vector",
-				DataType: entity.FieldTypeFloatVector,
-				TypeParams: map[string]string{
-					entity.TypeParamDim: "8",
-				},
-			},
-		},
-	}
-
-	err = c.CreateCollection(ctx, schema, 1) // only 1 shard
-	if err != nil {
-		log.Fatal("failed to create collection:", err.Error())
-	}
-
-	films, err := loadFilmCSV()
-	if err != nil {
-		log.Fatal("failed to load film data csv:", err.Error())
-	}
-
-	// row-base covert to column-base
-	ids := make([]int64, 0, len(films))
-	years := make([]int32, 0, len(films))
-	vectors := make([][]float32, 0, len(films))
-	// string field is not supported yet
-	idTitle := make(map[int64]string)
-	for idx, film := range films {
-		ids = append(ids, film.ID)
-		idTitle[film.ID] = film.Title
-		years = append(years, film.Year)
-		vectors = append(vectors, films[idx].Vector[:]) // prevent same vector
-	}
-	idColumn := entity.NewColumnInt64("ID", ids)
-	yearColumn := entity.NewColumnInt32("Year", years)
-	vectorColumn := entity.NewColumnFloatVector("Vector", 8, vectors)
-
-	// insert into default partition
-	_, err = c.Insert(ctx, collectionName, "", idColumn, yearColumn, vectorColumn)
-	if err != nil {
-		log.Fatal("failed to insert film data:", err.Error())
-	}
-	log.Println("insert completed")
-	ctx, cancel = context.WithTimeout(context.Background(), time.Second*120)
-	defer cancel()
-	err = c.Flush(ctx, collectionName, false)
-	if err != nil {
-		log.Fatal("failed to flush collection:", err.Error())
-	}
-	log.Println("flush completed")
-
-	// Now add index
-	idx, err := entity.NewIndexFlat(entity.L2)
-	if err != nil {
-		log.Fatal("fail to create ivf flat index:", err.Error())
-	}
-	err = c.CreateIndex(ctx, false, idx, v2.SetCollectionNameForCreateIndex(collectionName),
-		v2.SetFieldNameForCreateIndex("Vector"))
-	if err != nil {
-		log.Fatal("fail to create index:", err.Error())
-	}
-	log.Println("create index completed")
-
-	// create same index
-	err = c.CreateIndex(ctx, false, idx, v2.SetCollectionNameForCreateIndex(collectionName),
-		v2.SetFieldNameForCreateIndex("Vector"))
-	if err != nil {
-		log.Fatal("fail to create index:", err.Error())
-	}
-	log.Println("create index again completed")
-
-	indexes, err := c.DescribeIndex(ctx, v2.SetCollectionNameForDescribeIndex(collectionName))
-	if err != nil {
-		log.Fatal("fail to describe index:", err.Error())
-	}
-	log.Println("describe index success, indexes: ")
-	for _, index := range indexes {
-		log.Println(index)
-	}
-
-	// load collection with async=false
-	err = c.LoadCollection(ctx, collectionName, false)
-	if err != nil {
-		log.Fatal("failed to load collection:", err.Error())
-	}
-	log.Println("load collection completed")
-
-	searchFilm := films[0] // use first fim to search
-	vector := entity.FloatVector(searchFilm.Vector[:])
-	sp, _ := entity.NewIndexFlatSearchParam()
-	start := time.Now()
-	sr, err := c.Search(ctx, collectionName, []string{}, "Year > 1990", []string{"ID"}, []entity.Vector{vector}, "Vector",
-		entity.L2, 10, sp)
-	if err != nil {
-		log.Fatal("fail to search collection:", err.Error())
-	}
-	log.Println("search without index time elapsed:", time.Since(start))
-	for _, result := range sr {
-		var idColumn *entity.ColumnInt64
-		for _, field := range result.Fields {
-			if field.Name() == "ID" {
-				c, ok := field.(*entity.ColumnInt64)
-				if ok {
-					idColumn = c
-				}
-			}
-		}
-		if idColumn == nil {
-			log.Fatal("result field not math")
-		}
-		for i := 0; i < result.ResultCount; i++ {
-			id, err := idColumn.ValueByIdx(i)
-			if err != nil {
-				log.Fatal(err.Error())
-			}
-			title := idTitle[id]
-			fmt.Printf("file id: %d title: %s scores: %f\n", id, title, result.Scores[i])
-		}
-	}
-
-	err = c.ReleaseCollection(ctx, collectionName)
-	if err != nil {
-		log.Fatal("failed to release collection:", err.Error())
-	}
-	log.Println("release collection success")
-
-	err = c.DropIndex(ctx, v2.SetCollectionNameForDropIndex(collectionName))
-	if err != nil {
-		log.Fatal("failed to drop index:", err.Error())
-	}
-	log.Println("drop index success")
-
-	log.Println("create flat index")
-	idx2, err := entity.NewIndexIvfFlat(entity.L2, 2)
-	if err != nil {
-		log.Fatal("fail to create ivf flat index:", err.Error())
-	}
-	err = c.CreateIndex(ctx, false, idx2, v2.SetCollectionNameForCreateIndex(collectionName),
-		v2.SetFieldNameForCreateIndex("Vector"))
-	if err != nil {
-		log.Fatal("fail to create index:", err.Error())
-	}
-	log.Println("create index completed")
-
-	// load collection with async=false
-	err = c.LoadCollection(ctx, collectionName, false)
-	if err != nil {
-		log.Fatal("failed to load collection:", err.Error())
-	}
-	log.Println("load collection completed")
-
-	// do search again
-	start = time.Now()
-	sp2, _ := entity.NewIndexIvfFlatSearchParam(10)
-	sr, err = c.Search(ctx, collectionName, []string{}, "Year > 1990", []string{"ID"}, []entity.Vector{vector}, "Vector",
-		entity.L2, 10, sp2)
-	if err != nil {
-		log.Fatal("fail to search collection:", err.Error())
-	}
-	log.Println("search with index time elapsed:", time.Since(start))
-
-	err = c.ReleaseCollection(ctx, collectionName)
-	if err != nil {
-		log.Fatal("failed to release collection:", err.Error())
-	}
-	log.Println("release collection success")
-
-	err = c.DropIndex(ctx, v2.SetCollectionNameForDropIndex(collectionName))
-	if err != nil {
-		log.Fatal("failed to drop index:", err.Error())
-	}
-	log.Println("drop index success")
-
-	log.Println("drop index again")
-	err = c.DropIndex(ctx, v2.SetCollectionNameForDropIndex(collectionName))
-	if err != nil {
-		log.Fatal("failed to drop index:", err.Error())
-	}
-	log.Println("drop index success")
-	// clean up
-	_ = c.DropCollection(ctx, collectionName)
-	log.Println("drop collection success")
-}
-
-type film struct {
-	ID     int64
-	Title  string
-	Year   int32
-	Vector [8]float32 // fix length array
-}
-
-func loadFilmCSV() ([]film, error) {
-	f, err := os.Open("../../films.csv") // assume you are in examples/insert folder, if not, please change the path
-	if err != nil {
-		return []film{}, err
-	}
-	r := csv.NewReader(f)
-	raw, err := r.ReadAll()
-	if err != nil {
-		return []film{}, err
-	}
-	films := make([]film, 0, len(raw))
-	for _, line := range raw {
-		if len(line) < 4 { // insuffcient column
-			continue
-		}
-		fi := film{}
-		// ID
-		v, err := strconv.ParseInt(line[0], 10, 64)
-		if err != nil {
-			continue
-		}
-		fi.ID = v
-		// Title
-		fi.Title = line[1]
-		// Year
-		v, err = strconv.ParseInt(line[2], 10, 64)
-		if err != nil {
-			continue
-		}
-		fi.Year = int32(v)
-		// Vector
-		vectorStr := strings.ReplaceAll(line[3], "[", "")
-		vectorStr = strings.ReplaceAll(vectorStr, "]", "")
-		parts := strings.Split(vectorStr, ",")
-		if len(parts) != 8 { // dim must be 8
-			continue
-		}
-		for idx, part := range parts {
-			part = strings.TrimSpace(part)
-			v, err := strconv.ParseFloat(part, 32)
-			if err != nil {
-				continue
-			}
-			fi.Vector[idx] = float32(v)
-		}
-		films = append(films, fi)
-	}
-	return films, nil
-}


Test patch:
diff --git a/client/client_grpc_index_test.go b/client/client_grpc_index_test.go
index 1ed497c..744cb9d 100644
--- a/client/client_grpc_index_test.go
+++ b/client/client_grpc_index_test.go
@@ -64,6 +64,7 @@ func TestGrpcClientCreateIndex(t *testing.T) {
 				return resp, err
 			}
 			assert.Equal(t, testCollectionName, req.CollectionName)
+			assert.Equal(t, "test-index", req.IndexName)
 
 			resp.State = common.IndexState_InProgress
 			if time.Since(start) > time.Duration(buildTime)*time.Millisecond {
@@ -76,7 +77,7 @@ func TestGrpcClientCreateIndex(t *testing.T) {
 			return resp, err
 		})
 
-		assert.Nil(t, c.CreateIndex(ctx, testCollectionName, fieldName, idx, false))
+		assert.Nil(t, c.CreateIndex(ctx, testCollectionName, fieldName, idx, false, WithIndexName("test-index")))
 		assert.True(t, flag)
 
 		mock.DelInjection(MGetIndexState)
diff --git a/client/v2/client_grpc_index_test.go b/client/v2/client_grpc_index_test.go
deleted file mode 100644
index 56e195c..0000000
--- a/client/v2/client_grpc_index_test.go
+++ /dev/null
@@ -1,470 +0,0 @@
-// Copyright (C) 2019-2021 Zilliz. All rights reserved.
-//
-// 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
-//
-// http://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 v2
-
-import (
-	"context"
-	"errors"
-	"log"
-	"math/rand"
-	"net"
-	"testing"
-	"time"
-
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/test/bufconn"
-
-	"github.com/golang/protobuf/proto"
-	common "github.com/milvus-io/milvus-proto/go-api/commonpb"
-	server "github.com/milvus-io/milvus-proto/go-api/milvuspb"
-	"github.com/milvus-io/milvus-sdk-go/v2/client"
-	"github.com/milvus-io/milvus-sdk-go/v2/entity"
-	"github.com/stretchr/testify/assert"
-)
-
-const (
-	bufSzie = 1024 * 1024
-)
-
-var (
-	lis  *bufconn.Listener
-	mock *client.MockServer
-)
-
-// TestMain establishes mock grpc server to testing client behavior
-func TestMain(m *testing.M) {
-	rand.Seed(time.Now().Unix())
-	lis = bufconn.Listen(bufSzie)
-	s := grpc.NewServer()
-	mock = &client.MockServer{
-		Injections: make(map[client.ServiceMethod]client.TestInjection),
-	}
-	server.RegisterMilvusServiceServer(s, mock)
-	go func() {
-		if err := s.Serve(lis); err != nil {
-			log.Fatalf("Server exited with error: %v", err)
-		}
-	}()
-	m.Run()
-	//	lis.Close()
-}
-
-// use bufconn dialer
-func bufDialer(context.Context, string) (net.Conn, error) {
-	return lis.Dial()
-}
-
-func testClient(ctx context.Context, t *testing.T) Client {
-	c, err := NewGrpcClient(ctx, "bufnet", grpc.WithBlock(),
-		grpc.WithInsecure(), grpc.WithContextDialer(bufDialer))
-
-	if !assert.Nil(t, err) || !assert.NotNil(t, c) {
-		t.FailNow()
-	}
-	return c
-}
-
-func TestGrpcClient_CreateIndex(t *testing.T) {
-	ctx := context.Background()
-	c := testClient(ctx, t)
-
-	const (
-		collectionName   = "coll_index"
-		defaultIndexName = "_default_idx_101"
-		indexName        = "indexName"
-		emptyIndexName   = ""
-		fieldName        = "fieldName"
-	)
-
-	var (
-		flag  = false
-		count = 0
-	)
-
-	idx, err := entity.NewIndexHNSW(entity.L2, 16, 64)
-	assert.Nil(t, err)
-	if !assert.NotNil(t, idx) {
-		t.FailNow()
-	}
-	mock.SetInjection(client.MCreateIndex, func(_ context.Context, raw proto.Message) (proto.Message, error) {
-		req, ok := raw.(*server.CreateIndexRequest)
-		if !ok {
-			return client.BadRequestStatus()
-		}
-		assert.Equal(t, collectionName, req.GetCollectionName())
-		assert.Equal(t, fieldName, req.GetFieldName())
-		//assert.Equal(t, defaultIndexName, req.GetIndexName())
-		return client.SuccessStatus()
-	})
-
-	mock.SetInjection(client.MDescribeIndex, func(_ context.Context, message proto.Message) (proto.Message, error) {
-		var err2 error
-		req, ok := message.(*server.DescribeIndexRequest)
-		resp := &server.DescribeIndexResponse{}
-		if !ok {
-			resp.Status, err2 = client.BadRequestStatus()
-			return resp.Status, err2
-		}
-		assert.Equal(t, collectionName, req.GetCollectionName())
-		assert.Equal(t, fieldName, req.GetFieldName())
-		//assert.Equal(t, defaultIndexName, req.GetIndexName())
-
-		count++
-
-		if req.GetIndexName() == emptyIndexName {
-			resp.IndexDescriptions = []*server.IndexDescription{
-				{
-					IndexName:            defaultIndexName,
-					IndexID:              1,
-					Params:               entity.MapKvPairs(idx.Params()),
-					FieldName:            req.GetFieldName(),
-					IndexedRows:          9000,
-					TotalRows:            10000,
-					State:                common.IndexState_InProgress,
-					IndexStateFailReason: "",
-				},
-				{
-					IndexName:            indexName,
-					IndexID:              2,
-					Params:               entity.MapKvPairs(idx.Params()),
-					FieldName:            req.GetFieldName(),
-					IndexedRows:          2500,
-					TotalRows:            3000,
-					State:                common.IndexState_InProgress,
-					IndexStateFailReason: "",
-				},
-			}
-		} else {
-			resp.IndexDescriptions = []*server.IndexDescription{
-				{
-					IndexName:            req.GetIndexName(),
-					IndexID:              0,
-					Params:               entity.MapKvPairs(idx.Params()),
-					FieldName:            req.GetFieldName(),
-					IndexedRows:          9000,
-					TotalRows:            10000,
-					State:                common.IndexState_InProgress,
-					IndexStateFailReason: "",
-				},
-			}
-		}
-
-		if count >= 10 {
-			for i := range resp.GetIndexDescriptions() {
-				resp.IndexDescriptions[i].State = common.IndexState_Finished
-			}
-			flag = true
-		}
-
-		resp.Status, err2 = client.SuccessStatus()
-		return resp, err2
-	})
-
-	t.Run("normal", func(t *testing.T) {
-		err = c.CreateIndex(ctx, true, idx, SetCollectionNameForCreateIndex(collectionName),
-			SetFieldNameForCreateIndex(fieldName), SetIndexNameForCreateIndex(defaultIndexName))
-		assert.NoError(t, err)
-	})
-
-	t.Run("sync mode", func(t *testing.T) {
-		err = c.CreateIndex(ctx, false, idx, SetCollectionNameForCreateIndex(collectionName),
-			SetFieldNameForCreateIndex(fieldName), SetIndexNameForCreateIndex(defaultIndexName))
-		assert.NoError(t, err)
-		assert.True(t, flag)
-	})
-
-	t.Run("empty collection name", func(t *testing.T) {
-		err = c.CreateIndex(ctx, false, idx,
-			SetFieldNameForCreateIndex(fieldName), SetIndexNameForCreateIndex(defaultIndexName))
-		assert.Error(t, err)
-	})
-
-	t.Run("empty field name", func(t *testing.T) {
-		err = c.CreateIndex(ctx, false, idx, SetCollectionNameForCreateIndex(collectionName),
-			SetIndexNameForCreateIndex(defaultIndexName))
-		assert.Error(t, err)
-	})
-
-	t.Run("empty index name", func(t *testing.T) {
-		count = 0
-		flag = false
-		err = c.CreateIndex(ctx, false, idx, SetCollectionNameForCreateIndex(collectionName),
-			SetFieldNameForCreateIndex(fieldName))
-		assert.NoError(t, err)
-		assert.True(t, flag)
-	})
-
-	t.Run("index failed", func(t *testing.T) {
-		mock.SetInjection(client.MDescribeIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			var err2 error
-			req, ok := message.(*server.DescribeIndexRequest)
-			resp := &server.DescribeIndexResponse{}
-			if !ok {
-				resp.Status, err2 = client.BadRequestStatus()
-				return resp, err2
-			}
-			resp.IndexDescriptions = []*server.IndexDescription{
-				{
-					IndexName:            req.GetIndexName(),
-					IndexID:              1,
-					Params:               nil,
-					FieldName:            req.GetFieldName(),
-					IndexedRows:          1000,
-					TotalRows:            0,
-					State:                common.IndexState_Failed,
-					IndexStateFailReason: "",
-				},
-			}
-			return resp, err2
-		})
-
-		err = c.CreateIndex(ctx, false, idx, SetCollectionNameForCreateIndex(collectionName),
-			SetFieldNameForCreateIndex(fieldName), SetIndexNameForCreateIndex(defaultIndexName))
-		assert.Error(t, err)
-	})
-
-	t.Run("bad status", func(t *testing.T) {
-		mock.SetInjection(client.MDescribeIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			var err2 error
-			resp := &server.DescribeIndexResponse{}
-			resp.Status, err2 = client.BadStatus()
-			return resp, err2
-		})
-		err = c.CreateIndex(ctx, false, idx, SetCollectionNameForCreateIndex(collectionName),
-			SetFieldNameForCreateIndex(fieldName), SetIndexNameForCreateIndex(defaultIndexName))
-		assert.Error(t, err)
-
-		mock.SetInjection(client.MCreateIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			return client.BadStatus()
-		})
-
-		err = c.CreateIndex(ctx, false, idx, SetCollectionNameForCreateIndex(collectionName),
-			SetFieldNameForCreateIndex(fieldName), SetIndexNameForCreateIndex(defaultIndexName))
-		assert.Error(t, err)
-	})
-
-	t.Run("error", func(t *testing.T) {
-		mock.SetInjection(client.MDescribeIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			var err2 error
-			resp := &server.DescribeIndexResponse{}
-			resp.Status, err2 = client.BadRequestStatus()
-			return resp, err2
-		})
-		mock.SetInjection(client.MCreateIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			return client.SuccessStatus()
-		})
-
-		err = c.CreateIndex(ctx, false, idx, SetCollectionNameForCreateIndex(collectionName),
-			SetFieldNameForCreateIndex(fieldName), SetIndexNameForCreateIndex(defaultIndexName))
-		assert.Error(t, err)
-
-		mock.SetInjection(client.MCreateIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			return client.BadRequestStatus()
-		})
-
-		err = c.CreateIndex(ctx, false, idx, SetCollectionNameForCreateIndex(collectionName),
-			SetFieldNameForCreateIndex(fieldName), SetIndexNameForCreateIndex(defaultIndexName))
-		assert.Error(t, err)
-	})
-}
-
-func TestGrpcClient_DescribeIndex(t *testing.T) {
-	ctx := context.Background()
-	c := testClient(ctx, t)
-
-	const (
-		collectionName   = "coll_index"
-		defaultIndexName = "_default_idx_101"
-		indexName        = "indexName"
-		emptyIndexName   = ""
-		fieldName        = "fieldName"
-	)
-
-	idx, err := entity.NewIndexHNSW(entity.L2, 16, 64)
-	assert.Nil(t, err)
-	if !assert.NotNil(t, idx) {
-		t.FailNow()
-	}
-
-	t.Run("normal", func(t *testing.T) {
-		mock.SetInjection(client.MDescribeIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			var err2 error
-			req, ok := message.(*server.DescribeIndexRequest)
-			resp := &server.DescribeIndexResponse{}
-			if !ok {
-				resp.Status, err2 = client.BadRequestStatus()
-				return resp, err2
-			}
-			assert.Equal(t, collectionName, req.GetCollectionName())
-
-			if req.GetIndexName() == emptyIndexName {
-				resp.IndexDescriptions = []*server.IndexDescription{
-					{
-						IndexName:            defaultIndexName,
-						IndexID:              1,
-						Params:               entity.MapKvPairs(idx.Params()),
-						FieldName:            req.GetFieldName(),
-						IndexedRows:          9000,
-						TotalRows:            10000,
-						State:                common.IndexState_InProgress,
-						IndexStateFailReason: "",
-					},
-					{
-						IndexName:            indexName,
-						IndexID:              2,
-						Params:               entity.MapKvPairs(idx.Params()),
-						FieldName:            req.GetFieldName(),
-						IndexedRows:          2500,
-						TotalRows:            3000,
-						State:                common.IndexState_InProgress,
-						IndexStateFailReason: "",
-					},
-				}
-			} else {
-				resp.IndexDescriptions = []*server.IndexDescription{
-					{
-						IndexName:            req.GetIndexName(),
-						IndexID:              1,
-						Params:               entity.MapKvPairs(idx.Params()),
-						FieldName:            req.GetFieldName(),
-						IndexedRows:          9000,
-						TotalRows:            10000,
-						State:                common.IndexState_InProgress,
-						IndexStateFailReason: "",
-					},
-				}
-			}
-			resp.Status, err2 = client.SuccessStatus()
-			return resp, err2
-		})
-
-		indexes, err := c.DescribeIndex(ctx, SetCollectionNameForDescribeIndex(collectionName),
-			SetIndexNameForDescribeIndex(indexName))
-		assert.NoError(t, err)
-		assert.Equal(t, 1, len(indexes))
-		assert.Equal(t, indexName, indexes[0].GetIndexName())
-	})
-
-	t.Run("empty collection name", func(t *testing.T) {
-		indexes, err := c.DescribeIndex(ctx,
-			SetIndexNameForDescribeIndex(indexName))
-		assert.Error(t, err)
-		assert.Equal(t, 0, len(indexes))
-	})
-
-	t.Run("empty index name", func(t *testing.T) {
-		indexes, err := c.DescribeIndex(ctx, SetCollectionNameForDescribeIndex(collectionName))
-		assert.NoError(t, err)
-		assert.Equal(t, 2, len(indexes))
-	})
-
-	t.Run("bad status", func(t *testing.T) {
-		mock.SetInjection(client.MDescribeIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			return &server.DescribeIndexResponse{
-				Status: &common.Status{
-					ErrorCode: common.ErrorCode_IndexNotExist,
-					Reason:    "index not exist",
-				},
-			}, nil
-		})
-		indexes, err := c.DescribeIndex(ctx, SetCollectionNameForDescribeIndex(collectionName))
-		assert.Error(t, err)
-		assert.Equal(t, 0, len(indexes))
-	})
-
-	t.Run("error", func(t *testing.T) {
-		mock.SetInjection(client.MDescribeIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			return &server.DescribeIndexResponse{
-				Status: &common.Status{
-					ErrorCode: common.ErrorCode_UnexpectedError,
-					Reason:    "",
-				},
-			}, errors.New("error")
-		})
-		indexes, err := c.DescribeIndex(ctx, SetCollectionNameForDescribeIndex(collectionName))
-		assert.Error(t, err)
-		assert.Equal(t, 0, len(indexes))
-	})
-}
-
-func TestGrpcClient_DropIndex(t *testing.T) {
-	ctx := context.Background()
-	c := testClient(ctx, t)
-
-	const (
-		collectionName   = "coll_index"
-		defaultIndexName = "_default_idx_101"
-		indexName        = "indexName"
-		emptyIndexName   = ""
-		fieldName        = "fieldName"
-	)
-
-	idx, err := entity.NewIndexHNSW(entity.L2, 16, 64)
-	assert.Nil(t, err)
-	if !assert.NotNil(t, idx) {
-		t.FailNow()
-	}
-
-	mock.SetInjection(client.MDropIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-		req, ok := message.(*server.DropIndexRequest)
-		if !ok {
-			return client.BadRequestStatus()
-		}
-		assert.Equal(t, collectionName, req.GetCollectionName())
-
-		return client.SuccessStatus()
-	})
-
-	t.Run("normal", func(t *testing.T) {
-		err = c.DropIndex(ctx, SetCollectionNameForDropIndex(collectionName), SetFieldNameForDroIndex(fieldName),
-			SetIndexNameForDropIndex(indexName))
-		assert.NoError(t, err)
-	})
-
-	t.Run("empty collection name", func(t *testing.T) {
-		err = c.DropIndex(ctx, SetFieldNameForDroIndex(fieldName),
-			SetIndexNameForDropIndex(indexName))
-		assert.Error(t, err)
-	})
-
-	t.Run("empty field name", func(t *testing.T) {
-		err = c.DropIndex(ctx, SetCollectionNameForDropIndex(collectionName), SetIndexNameForDropIndex(indexName))
-		assert.NoError(t, err)
-	})
-
-	t.Run("empty index name", func(t *testing.T) {
-		err = c.DropIndex(ctx, SetCollectionNameForDropIndex(collectionName), SetFieldNameForDroIndex(fieldName))
-		assert.NoError(t, err)
-
-		err = c.DropIndex(ctx, SetCollectionNameForDropIndex(collectionName))
-		assert.NoError(t, err)
-	})
-
-	t.Run("bad status", func(t *testing.T) {
-		mock.SetInjection(client.MDropIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			return client.BadStatus()
-		})
-		err = c.DropIndex(ctx, SetCollectionNameForDropIndex(collectionName))
-		assert.Error(t, err)
-	})
-
-	t.Run("error", func(t *testing.T) {
-		mock.SetInjection(client.MDropIndex, func(ctx context.Context, message proto.Message) (proto.Message, error) {
-			return &common.Status{
-				ErrorCode: common.ErrorCode_UnexpectedError,
-				Reason:    "fail",
-			}, errors.New("error")
-		})
-		err = c.DropIndex(ctx, SetCollectionNameForDropIndex(collectionName))
-		assert.Error(t, err)
-	})
-}
diff --git a/scripts/run_go_unittest.sh b/scripts/run_go_unittest.sh
index 6b7be20..8c51bcd 100755
--- a/scripts/run_go_unittest.sh
+++ b/scripts/run_go_unittest.sh
@@ -8,9 +8,10 @@ for d in $(go list ./... | grep -v vendor/examples/tests); do
     if [[ "$d" == *examples*  ]]; then
         continue
     fi
-    if [[ "$d" == *tests* ]]; then
+    if [[ "$d" == *test* ]]; then
         continue
     fi
+
     echo $d
     go test -race -coverprofile=coverage.out -covermode=atomic "$d"
     if [[ -f coverage.out ]]; then
diff --git a/test/base/milvus_client.go b/test/base/milvus_client.go
index 0da54d7..45d2e01 100644
--- a/test/base/milvus_client.go
+++ b/test/base/milvus_client.go
@@ -4,9 +4,7 @@ import (
 	"context"
 	"log"
 
-	server "github.com/milvus-io/milvus-proto/go-api/milvuspb"
 	"github.com/milvus-io/milvus-sdk-go/v2/client"
-	v2 "github.com/milvus-io/milvus-sdk-go/v2/client/v2"
 	"github.com/milvus-io/milvus-sdk-go/v2/entity"
 
 	"google.golang.org/grpc"
@@ -26,12 +24,12 @@ func postResponse(funcName string, err error, res ...interface{}) {
 }
 
 type MilvusClient struct {
-	mClient v2.Client
+	mClient client.Client
 }
 
 func NewMilvusClient(ctx context.Context, addr string, dialOptions ...grpc.DialOption) (*MilvusClient, error) {
 	preRequest("NewGrpcClient", addr, dialOptions)
-	mClient, err := v2.NewGrpcClient(ctx, addr, dialOptions...)
+	mClient, err := client.NewGrpcClient(ctx, addr, dialOptions...)
 	postResponse("NewGrpcClient", err, mClient)
 	return &MilvusClient{
 		mClient,
@@ -120,18 +118,18 @@ func (mc *MilvusClient) GetPersistentSegmentInfo(ctx context.Context, collName s
 
 // TODO collName, indexName, fieldName in CreateIndexRequestOption
 // Create Index
-func (mc *MilvusClient) CreateIndex(ctx context.Context, async bool, idx entity.Index, opts ...v2.CreateIndexRequestOption) error {
+func (mc *MilvusClient) CreateIndex(ctx context.Context, collectionName string, fieldName string, async bool, idx entity.Index, opts ...client.IndexOption) error {
 	preRequest("CreateIndex", async, idx, opts)
-	err := mc.mClient.CreateIndex(ctx, async, idx, opts...)
+	err := mc.mClient.CreateIndex(ctx, collectionName, fieldName, idx, async, opts...)
 	postResponse("CreateIndex", err)
 	return err
 }
 
 // TODO milvuspb server IndexDescription
 //Describe Index
-func (mc *MilvusClient) DescribeIndex(ctx context.Context, opts ...v2.DescribeIndexRequestOption) ([]*server.IndexDescription, error) {
+func (mc *MilvusClient) DescribeIndex(ctx context.Context, collectionName string, fieldName string, opts ...client.IndexOption) ([]entity.Index, error) {
 	preRequest("DescribeIndex", opts)
-	indexes, err := mc.mClient.DescribeIndex(ctx, opts...)
+	indexes, err := mc.mClient.DescribeIndex(ctx, collectionName, fieldName, opts...)
 	postResponse("DescribeIndex", err, indexes)
 	return indexes, err
 }