// Licensed to the LF AI & Data foundation under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 querynode

import (
	"context"
	"log"
	"math"
	"sync"
	"testing"

	"github.com/golang/protobuf/proto"
	"github.com/stretchr/testify/assert"

	"github.com/milvus-io/milvus/internal/common"
	"github.com/milvus-io/milvus/internal/proto/commonpb"
	"github.com/milvus-io/milvus/internal/proto/datapb"
	"github.com/milvus-io/milvus/internal/proto/milvuspb"
	"github.com/milvus-io/milvus/internal/proto/planpb"
	"github.com/milvus-io/milvus/internal/proto/schemapb"
	"github.com/milvus-io/milvus/internal/proto/segcorepb"
)

//-------------------------------------------------------------------------------------- constructor and destructor
func TestSegment_newSegment(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)
	deleteSegment(segment)
	deleteCollection(collection)

	t.Run("test invalid type", func(t *testing.T) {
		s := newSegment(collection,
			defaultSegmentID,
			defaultPartitionID,
			collectionID, "", segmentTypeInvalid, true)
		assert.Nil(t, s)
		s = newSegment(collection,
			defaultSegmentID,
			defaultPartitionID,
			collectionID, "", 100, true)
		assert.Nil(t, s)
	})
}

func TestSegment_deleteSegment(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	deleteSegment(segment)
	deleteCollection(collection)

	t.Run("test delete nil ptr", func(t *testing.T) {
		s, err := genSimpleSealedSegment()
		assert.NoError(t, err)
		s.segmentPtr = nil
		deleteSegment(s)
	})
}

//-------------------------------------------------------------------------------------- stats functions
func TestSegment_getRowCount(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	ids := []int64{1, 2, 3}
	timestamps := []Timestamp{0, 0, 0}

	const DIM = 16
	const N = 3
	var vec = [DIM]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
	var rawData []byte
	for _, ele := range vec {
		buf := make([]byte, 4)
		common.Endian.PutUint32(buf, math.Float32bits(ele))
		rawData = append(rawData, buf...)
	}
	bs := make([]byte, 4)
	common.Endian.PutUint32(bs, 1)
	rawData = append(rawData, bs...)
	var records []*commonpb.Blob
	for i := 0; i < N; i++ {
		blob := &commonpb.Blob{
			Value: rawData,
		}
		records = append(records, blob)
	}

	offset, err := segment.segmentPreInsert(N)
	assert.Nil(t, err)
	assert.GreaterOrEqual(t, offset, int64(0))

	err = segment.segmentInsert(offset, &ids, &timestamps, &records)
	assert.NoError(t, err)

	rowCount := segment.getRowCount()
	assert.Equal(t, int64(N), rowCount)

	deleteSegment(segment)
	deleteCollection(collection)

	t.Run("test getRowCount nil ptr", func(t *testing.T) {
		s, err := genSimpleSealedSegment()
		assert.NoError(t, err)
		s.segmentPtr = nil
		res := s.getRowCount()
		assert.Equal(t, int64(-1), res)
	})
}

func TestSegment_retrieve(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	ids := []int64{}
	timestamps := []Timestamp{}
	const DIM = 16
	const N = 100
	var records []*commonpb.Blob
	for i := 0; i < N; i++ {
		ids = append(ids, int64(i))
		timestamps = append(timestamps, 0)
		var vec = [DIM]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
		var rawData []byte
		for _, ele := range vec {
			buf := make([]byte, 4)
			common.Endian.PutUint32(buf, math.Float32bits(ele+float32(i)*float32(N)))
			rawData = append(rawData, buf...)
		}
		bs := make([]byte, 4)
		common.Endian.PutUint32(bs, uint32(i+1))
		rawData = append(rawData, bs...)
		blob := &commonpb.Blob{
			Value: rawData,
		}
		records = append(records, blob)
	}
	offset, err := segment.segmentPreInsert(N)
	assert.Nil(t, err)
	assert.Equal(t, offset, int64(0))
	err = segment.segmentInsert(offset, &ids, &timestamps, &records)
	assert.NoError(t, err)

	planNode := &planpb.PlanNode{
		Node: &planpb.PlanNode_Predicates{
			Predicates: &planpb.Expr{
				Expr: &planpb.Expr_TermExpr{
					TermExpr: &planpb.TermExpr{
						ColumnInfo: &planpb.ColumnInfo{
							FieldId:  101,
							DataType: schemapb.DataType_Int32,
						},
						Values: []*planpb.GenericValue{
							{
								Val: &planpb.GenericValue_Int64Val{
									Int64Val: 1,
								},
							},
							{
								Val: &planpb.GenericValue_Int64Val{
									Int64Val: 2,
								},
							},
							{
								Val: &planpb.GenericValue_Int64Val{
									Int64Val: 3,
								},
							},
						},
					},
				},
			},
		},
		OutputFieldIds: []FieldID{101},
	}
	// reqIds := &segcorepb.RetrieveRequest{
	// 	Ids: &schemapb.IDs{
	// 		IdField: &schemapb.IDs_IntId{
	// 			IntId: &schemapb.LongArray{
	// 				Data: []int64{2, 3, 1},
	// 			},
	// 		},
	// 	},
	// 	OutputFieldsId: []int64{100},
	// }
	planExpr, err := proto.Marshal(planNode)
	assert.NoError(t, err)
	plan, err := createRetrievePlanByExpr(collection, planExpr, 100)
	defer plan.delete()
	assert.NoError(t, err)

	res, err := segment.retrieve(plan)
	assert.NoError(t, err)

	assert.Equal(t, res.GetFieldsData()[0].GetScalars().Data.(*schemapb.ScalarField_IntData).IntData.Data, []int32{1, 2, 3})
}

func TestSegment_getDeletedCount(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	ids := []int64{1, 2, 3}
	timestamps := []uint64{0, 0, 0}

	const DIM = 16
	const N = 3
	var vec = [DIM]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
	var rawData []byte
	for _, ele := range vec {
		buf := make([]byte, 4)
		common.Endian.PutUint32(buf, math.Float32bits(ele))
		rawData = append(rawData, buf...)
	}
	bs := make([]byte, 4)
	common.Endian.PutUint32(bs, 1)
	rawData = append(rawData, bs...)
	var records []*commonpb.Blob
	for i := 0; i < N; i++ {
		blob := &commonpb.Blob{
			Value: rawData,
		}
		records = append(records, blob)
	}

	offsetInsert, err := segment.segmentPreInsert(N)
	assert.Nil(t, err)
	assert.GreaterOrEqual(t, offsetInsert, int64(0))

	err = segment.segmentInsert(offsetInsert, &ids, &timestamps, &records)
	assert.NoError(t, err)

	var offsetDelete = segment.segmentPreDelete(10)
	assert.GreaterOrEqual(t, offsetDelete, int64(0))

	err = segment.segmentDelete(offsetDelete, &ids, &timestamps)
	assert.NoError(t, err)

	var deletedCount = segment.getDeletedCount()
	// TODO: assert.Equal(t, deletedCount, len(ids))
	assert.Equal(t, deletedCount, int64(0))

	deleteCollection(collection)

	t.Run("test getDeletedCount nil ptr", func(t *testing.T) {
		s, err := genSimpleSealedSegment()
		assert.NoError(t, err)
		s.segmentPtr = nil
		res := s.getDeletedCount()
		assert.Equal(t, int64(-1), res)
	})
}

func TestSegment_getMemSize(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	ids := []int64{1, 2, 3}
	timestamps := []uint64{0, 0, 0}

	const DIM = 16
	const N = 3
	var vec = [DIM]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
	var rawData []byte
	for _, ele := range vec {
		buf := make([]byte, 4)
		common.Endian.PutUint32(buf, math.Float32bits(ele))
		rawData = append(rawData, buf...)
	}
	bs := make([]byte, 4)
	common.Endian.PutUint32(bs, 1)
	rawData = append(rawData, bs...)
	var records []*commonpb.Blob
	for i := 0; i < N; i++ {
		blob := &commonpb.Blob{
			Value: rawData,
		}
		records = append(records, blob)
	}

	offset, err := segment.segmentPreInsert(N)
	assert.Nil(t, err)
	assert.GreaterOrEqual(t, offset, int64(0))

	err = segment.segmentInsert(offset, &ids, &timestamps, &records)
	assert.NoError(t, err)

	var memSize = segment.getMemSize()
	assert.Equal(t, memSize, int64(2785280))

	deleteSegment(segment)
	deleteCollection(collection)
}

//-------------------------------------------------------------------------------------- dm & search functions
func TestSegment_segmentInsert(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)
	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	ids := []int64{1, 2, 3}
	timestamps := []uint64{0, 0, 0}

	const DIM = 16
	const N = 3
	var vec = [DIM]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
	var rawData []byte
	for _, ele := range vec {
		buf := make([]byte, 4)
		common.Endian.PutUint32(buf, math.Float32bits(ele))
		rawData = append(rawData, buf...)
	}
	bs := make([]byte, 4)
	common.Endian.PutUint32(bs, 1)
	rawData = append(rawData, bs...)
	var records []*commonpb.Blob
	for i := 0; i < N; i++ {
		blob := &commonpb.Blob{
			Value: rawData,
		}
		records = append(records, blob)
	}

	offset, err := segment.segmentPreInsert(N)
	assert.Nil(t, err)
	assert.GreaterOrEqual(t, offset, int64(0))

	err = segment.segmentInsert(offset, &ids, &timestamps, &records)
	assert.NoError(t, err)
	deleteSegment(segment)
	deleteCollection(collection)

	t.Run("test nil segment", func(t *testing.T) {
		segment, err := genSimpleSealedSegment()
		assert.NoError(t, err)
		segment.setType(segmentTypeGrowing)
		segment.segmentPtr = nil
		err = segment.segmentInsert(0, nil, nil, nil)
		assert.Error(t, err)
	})

	t.Run("test invalid segment type", func(t *testing.T) {
		segment, err := genSimpleSealedSegment()
		assert.NoError(t, err)
		err = segment.segmentInsert(0, nil, nil, nil)
		assert.NoError(t, err)
	})
}

func TestSegment_segmentDelete(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	ids := []int64{1, 2, 3}
	timestamps := []uint64{0, 0, 0}

	const DIM = 16
	const N = 3
	var vec = [DIM]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
	var rawData []byte
	for _, ele := range vec {
		buf := make([]byte, 4)
		common.Endian.PutUint32(buf, math.Float32bits(ele))
		rawData = append(rawData, buf...)
	}
	bs := make([]byte, 4)
	common.Endian.PutUint32(bs, 1)
	rawData = append(rawData, bs...)
	var records []*commonpb.Blob
	for i := 0; i < N; i++ {
		blob := &commonpb.Blob{
			Value: rawData,
		}
		records = append(records, blob)
	}

	offsetInsert, err := segment.segmentPreInsert(N)
	assert.Nil(t, err)
	assert.GreaterOrEqual(t, offsetInsert, int64(0))

	err = segment.segmentInsert(offsetInsert, &ids, &timestamps, &records)
	assert.NoError(t, err)

	var offsetDelete = segment.segmentPreDelete(10)
	assert.GreaterOrEqual(t, offsetDelete, int64(0))

	err = segment.segmentDelete(offsetDelete, &ids, &timestamps)
	assert.NoError(t, err)

	deleteCollection(collection)
}

func TestSegment_segmentSearch(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	ids := []int64{1, 2, 3}
	timestamps := []uint64{0, 0, 0}

	const DIM = 16
	const N = 3
	var vec = [DIM]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
	var rawData []byte
	for _, ele := range vec {
		buf := make([]byte, 4)
		common.Endian.PutUint32(buf, math.Float32bits(ele))
		rawData = append(rawData, buf...)
	}
	bs := make([]byte, 4)
	common.Endian.PutUint32(bs, 1)
	rawData = append(rawData, bs...)
	var records []*commonpb.Blob
	for i := 0; i < N; i++ {
		blob := &commonpb.Blob{
			Value: rawData,
		}
		records = append(records, blob)
	}

	offset, err := segment.segmentPreInsert(N)
	assert.Nil(t, err)
	assert.GreaterOrEqual(t, offset, int64(0))

	err = segment.segmentInsert(offset, &ids, &timestamps, &records)
	assert.NoError(t, err)
	dslString := "{\"bool\": { \n\"vector\": {\n \"vec\": {\n \"metric_type\": \"L2\", \n \"params\": {\n \"nprobe\": 10 \n},\n \"query\": \"$0\",\n \"topk\": 10 \n,\"round_decimal\": 6\n } \n } \n } \n }"
	var searchRawData []byte
	for _, ele := range vec {
		buf := make([]byte, 4)
		common.Endian.PutUint32(buf, math.Float32bits(ele))
		searchRawData = append(searchRawData, buf...)
	}
	placeholderValue := milvuspb.PlaceholderValue{
		Tag:    "$0",
		Type:   milvuspb.PlaceholderType_FloatVector,
		Values: [][]byte{searchRawData},
	}

	placeholderGroup := milvuspb.PlaceholderGroup{
		Placeholders: []*milvuspb.PlaceholderValue{&placeholderValue},
	}

	placeHolderGroupBlob, err := proto.Marshal(&placeholderGroup)
	if err != nil {
		log.Print("marshal placeholderGroup failed")
	}

	travelTimestamp := Timestamp(1020)
	plan, err := createSearchPlan(collection, dslString)
	assert.NoError(t, err)
	holder, err := parseSearchRequest(plan, placeHolderGroupBlob)
	assert.NoError(t, err)
	placeholderGroups := make([]*searchRequest, 0)
	placeholderGroups = append(placeholderGroups, holder)

	searchResults := make([]*SearchResult, 0)
	searchResult, err := segment.search(plan, placeholderGroups, []Timestamp{travelTimestamp})
	assert.Nil(t, err)
	searchResults = append(searchResults, searchResult)

	///////////////////////////////////
	numSegment := int64(len(searchResults))
	err = reduceSearchResultsAndFillData(plan, searchResults, numSegment)
	assert.NoError(t, err)
	marshaledHits, err := reorganizeSearchResults(searchResults, numSegment)
	assert.NoError(t, err)
	hitsBlob, err := marshaledHits.getHitsBlob()
	assert.NoError(t, err)

	var placeHolderOffset int64
	for index := range placeholderGroups {
		hitBlobSizePeerQuery, err := marshaledHits.hitBlobSizeInGroup(int64(index))
		assert.NoError(t, err)
		hits := make([][]byte, 0)
		for _, len := range hitBlobSizePeerQuery {
			hits = append(hits, hitsBlob[placeHolderOffset:placeHolderOffset+len])
			placeHolderOffset += len
		}
	}

	deleteSearchResults(searchResults)
	deleteMarshaledHits(marshaledHits)
	///////////////////////////////////

	plan.delete()
	holder.delete()
	deleteSegment(segment)
	deleteCollection(collection)
}

//-------------------------------------------------------------------------------------- preDm functions
func TestSegment_segmentPreInsert(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	const DIM = 16
	const N = 3
	var vec = [DIM]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
	var rawData []byte
	for _, ele := range vec {
		buf := make([]byte, 4)
		common.Endian.PutUint32(buf, math.Float32bits(ele))
		rawData = append(rawData, buf...)
	}
	bs := make([]byte, 4)
	common.Endian.PutUint32(bs, 1)
	rawData = append(rawData, bs...)
	var records []*commonpb.Blob
	for i := 0; i < N; i++ {
		blob := &commonpb.Blob{
			Value: rawData,
		}
		records = append(records, blob)
	}

	offset, err := segment.segmentPreInsert(N)
	assert.Nil(t, err)
	assert.GreaterOrEqual(t, offset, int64(0))

	deleteSegment(segment)
	deleteCollection(collection)
}

func TestSegment_segmentPreDelete(t *testing.T) {
	collectionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)

	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	segmentID := UniqueID(0)
	segment := newSegment(collection, segmentID, defaultPartitionID, collectionID, "", segmentTypeGrowing, true)
	assert.Equal(t, segmentID, segment.segmentID)

	ids := []int64{1, 2, 3}
	timestamps := []uint64{0, 0, 0}

	const DIM = 16
	const N = 3
	var vec = [DIM]float32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
	var rawData []byte
	for _, ele := range vec {
		buf := make([]byte, 4)
		common.Endian.PutUint32(buf, math.Float32bits(ele))
		rawData = append(rawData, buf...)
	}
	bs := make([]byte, 4)
	common.Endian.PutUint32(bs, 1)
	rawData = append(rawData, bs...)
	var records []*commonpb.Blob
	for i := 0; i < N; i++ {
		blob := &commonpb.Blob{
			Value: rawData,
		}
		records = append(records, blob)
	}

	offsetInsert, err := segment.segmentPreInsert(N)
	assert.Nil(t, err)
	assert.GreaterOrEqual(t, offsetInsert, int64(0))

	err = segment.segmentInsert(offsetInsert, &ids, &timestamps, &records)
	assert.NoError(t, err)

	var offsetDelete = segment.segmentPreDelete(10)
	assert.GreaterOrEqual(t, offsetDelete, int64(0))

	deleteSegment(segment)
	deleteCollection(collection)
}

func TestSegment_segmentLoadDeletedRecord(t *testing.T) {
	fieldParam := constFieldParam{
		id:       100,
		dataType: schemapb.DataType_Int64,
	}
	field := genPKField(fieldParam)
	schema := &schemapb.CollectionSchema{
		Name:   defaultCollectionName,
		AutoID: false,
		Fields: []*schemapb.FieldSchema{
			field,
		},
	}

	seg := newSegment(newCollection(defaultCollectionID, schema),
		defaultSegmentID,
		defaultPartitionID,
		defaultCollectionID,
		defaultDMLChannel,
		segmentTypeSealed,
		true)
	pks := []IntPrimaryKey{1, 2, 3}
	timestamps := []Timestamp{10, 10, 10}
	var rowCount int64 = 3
	error := seg.segmentLoadDeletedRecord(pks, timestamps, rowCount)
	assert.NoError(t, error)
}

func TestSegment_segmentLoadFieldData(t *testing.T) {
	genSchemas := func(dataType schemapb.DataType) (*schemapb.CollectionSchema, *schemapb.CollectionSchema) {
		constField := constFieldParam{
			id: 101,
		}
		constField.dataType = dataType
		field := genConstantField(constField)
		schema1 := &schemapb.CollectionSchema{
			Name:   defaultCollectionName,
			AutoID: true,
			Fields: []*schemapb.FieldSchema{
				field,
			},
		}

		fieldUID := genConstantField(uidField)
		fieldTimestamp := genConstantField(timestampField)
		schema2 := &schemapb.CollectionSchema{
			Name:   defaultCollectionName,
			AutoID: true,
			Fields: []*schemapb.FieldSchema{
				fieldUID,
				fieldTimestamp,
				field,
			},
		}
		return schema1, schema2
	}

	t.Run("test bool", func(t *testing.T) {
		schemaForCreate, schemaForLoad := genSchemas(schemapb.DataType_Bool)
		_, err := genSealedSegment(schemaForCreate,
			schemaForLoad,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			defaultMsgLength)
		assert.NoError(t, err)

		_, err = genSealedSegment(schemaForCreate,
			schemaForCreate,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			0)
		assert.Error(t, err)
	})

	t.Run("test int8", func(t *testing.T) {
		schemaForCreate, schemaForLoad := genSchemas(schemapb.DataType_Int8)
		_, err := genSealedSegment(schemaForCreate,
			schemaForLoad,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			defaultMsgLength)
		assert.NoError(t, err)

		_, err = genSealedSegment(schemaForCreate,
			schemaForCreate,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			0)
		assert.Error(t, err)
	})

	t.Run("test int16", func(t *testing.T) {
		schemaForCreate, schemaForLoad := genSchemas(schemapb.DataType_Int16)
		_, err := genSealedSegment(schemaForCreate,
			schemaForLoad,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			defaultMsgLength)
		assert.NoError(t, err)

		_, err = genSealedSegment(schemaForCreate,
			schemaForCreate,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			0)
		assert.Error(t, err)
	})

	t.Run("test int32", func(t *testing.T) {
		schemaForCreate, schemaForLoad := genSchemas(schemapb.DataType_Int32)
		_, err := genSealedSegment(schemaForCreate,
			schemaForLoad,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			defaultMsgLength)
		assert.NoError(t, err)

		_, err = genSealedSegment(schemaForCreate,
			schemaForCreate,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			0)
		assert.Error(t, err)
	})

	t.Run("test int64", func(t *testing.T) {
		schemaForCreate, schemaForLoad := genSchemas(schemapb.DataType_Int64)
		_, err := genSealedSegment(schemaForCreate,
			schemaForLoad,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			defaultMsgLength)
		assert.NoError(t, err)

		_, err = genSealedSegment(schemaForCreate,
			schemaForCreate,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			0)
		assert.Error(t, err)
	})

	t.Run("test float", func(t *testing.T) {
		schemaForCreate, schemaForLoad := genSchemas(schemapb.DataType_Float)
		_, err := genSealedSegment(schemaForCreate,
			schemaForLoad,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			defaultMsgLength)
		assert.NoError(t, err)

		_, err = genSealedSegment(schemaForCreate,
			schemaForCreate,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			0)
		assert.Error(t, err)
	})

	t.Run("test double", func(t *testing.T) {
		schemaForCreate, schemaForLoad := genSchemas(schemapb.DataType_Double)
		_, err := genSealedSegment(schemaForCreate,
			schemaForLoad,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			defaultMsgLength)
		assert.NoError(t, err)

		_, err = genSealedSegment(schemaForCreate,
			schemaForCreate,
			defaultCollectionID,
			defaultPartitionID,
			defaultSegmentID,
			defaultDMLChannel,
			0)
		assert.Error(t, err)
	})
}

func TestSegment_ConcurrentOperation(t *testing.T) {
	const N = 16
	var ages = []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}

	collectionID := UniqueID(0)
	partitionID := UniqueID(0)
	collectionMeta := genTestCollectionMeta(collectionID, false)
	collection := newCollection(collectionMeta.ID, collectionMeta.Schema)
	assert.Equal(t, collection.ID(), collectionID)

	wg := sync.WaitGroup{}
	for i := 0; i < 100; i++ {
		segmentID := UniqueID(i)
		segment := newSegment(collection, segmentID, partitionID, collectionID, "", segmentTypeSealed, true)
		assert.Equal(t, segmentID, segment.segmentID)
		assert.Equal(t, partitionID, segment.partitionID)

		wg.Add(2)
		go func() {
			deleteSegment(segment)
			wg.Done()
		}()
		go func() {
			// segmentLoadFieldData result error may be nil or not, we just expected this test would not crash.
			_ = segment.segmentLoadFieldData(101, N, ages)
			wg.Done()
		}()
	}
	wg.Wait()
	deleteCollection(collection)
}

func TestSegment_indexInfoTest(t *testing.T) {
	t.Run("Test_valid", func(t *testing.T) {
		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		tSafe := newTSafeReplica()
		h, err := genSimpleHistorical(ctx, tSafe)
		assert.NoError(t, err)

		seg, err := h.replica.getSegmentByID(defaultSegmentID)
		assert.NoError(t, err)

		fieldID := simpleVecField.id

		seg.setIndexInfo(fieldID, &indexInfo{})

		indexName := "query-node-test-index"
		err = seg.setIndexName(fieldID, indexName)
		assert.NoError(t, err)
		name := seg.getIndexName(fieldID)
		assert.Equal(t, indexName, name)

		indexParam := make(map[string]string)
		indexParam["index_type"] = "IVF_PQ"
		indexParam["index_mode"] = "cpu"
		err = seg.setIndexParam(fieldID, indexParam)
		assert.NoError(t, err)
		param := seg.getIndexParams(fieldID)
		assert.Equal(t, len(indexParam), len(param))
		assert.Equal(t, indexParam["index_type"], param["index_type"])
		assert.Equal(t, indexParam["index_mode"], param["index_mode"])

		indexPaths := []string{"query-node-test-index-path"}
		err = seg.setIndexPaths(fieldID, indexPaths)
		assert.NoError(t, err)
		paths := seg.getIndexPaths(fieldID)
		assert.Equal(t, len(indexPaths), len(paths))
		assert.Equal(t, indexPaths[0], paths[0])

		indexID := UniqueID(0)
		err = seg.setIndexID(fieldID, indexID)
		assert.NoError(t, err)
		id := seg.getIndexID(fieldID)
		assert.Equal(t, indexID, id)

		buildID := UniqueID(0)
		err = seg.setBuildID(fieldID, buildID)
		assert.NoError(t, err)
		id = seg.getBuildID(fieldID)
		assert.Equal(t, buildID, id)

		// TODO: add match index test
	})

	t.Run("Test_invalid", func(t *testing.T) {
		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		tSafe := newTSafeReplica()
		h, err := genSimpleHistorical(ctx, tSafe)
		assert.NoError(t, err)

		seg, err := h.replica.getSegmentByID(defaultSegmentID)
		assert.NoError(t, err)

		fieldID := simpleVecField.id

		indexName := "query-node-test-index"
		err = seg.setIndexName(fieldID, indexName)
		assert.Error(t, err)
		name := seg.getIndexName(fieldID)
		assert.Equal(t, "", name)

		indexParam := make(map[string]string)
		indexParam["index_type"] = "IVF_PQ"
		indexParam["index_mode"] = "cpu"
		err = seg.setIndexParam(fieldID, indexParam)
		assert.Error(t, err)
		err = seg.setIndexParam(fieldID, nil)
		assert.Error(t, err)
		param := seg.getIndexParams(fieldID)
		assert.Nil(t, param)

		indexPaths := []string{"query-node-test-index-path"}
		err = seg.setIndexPaths(fieldID, indexPaths)
		assert.Error(t, err)
		paths := seg.getIndexPaths(fieldID)
		assert.Nil(t, paths)

		indexID := UniqueID(0)
		err = seg.setIndexID(fieldID, indexID)
		assert.Error(t, err)
		id := seg.getIndexID(fieldID)
		assert.Equal(t, int64(-1), id)

		buildID := UniqueID(0)
		err = seg.setBuildID(fieldID, buildID)
		assert.Error(t, err)
		id = seg.getBuildID(fieldID)
		assert.Equal(t, int64(-1), id)

		seg.setIndexInfo(fieldID, &indexInfo{
			readyLoad: true,
		})

		ready := seg.checkIndexReady(fieldID)
		assert.True(t, ready)
		ready = seg.checkIndexReady(FieldID(1000))
		assert.False(t, ready)
	})
}

func TestSegment_BasicMetrics(t *testing.T) {
	schema := genSimpleSegCoreSchema()
	collection := newCollection(defaultCollectionID, schema)
	segment := newSegment(collection,
		defaultSegmentID,
		defaultPartitionID,
		defaultCollectionID,
		defaultDMLChannel,
		segmentTypeSealed,
		true)

	t.Run("test enable index", func(t *testing.T) {
		segment.setEnableIndex(true)
		enable := segment.getEnableIndex()
		assert.True(t, enable)
	})

	t.Run("test id binlog row size", func(t *testing.T) {
		size := int64(1024)
		segment.setIDBinlogRowSizes([]int64{size})
		sizes := segment.getIDBinlogRowSizes()
		assert.Len(t, sizes, 1)
		assert.Equal(t, size, sizes[0])
	})

	t.Run("test type", func(t *testing.T) {
		sType := segmentTypeGrowing
		segment.setType(sType)
		resType := segment.getType()
		assert.Equal(t, sType, resType)
	})

	t.Run("test onService", func(t *testing.T) {
		segment.setOnService(false)
		resOnService := segment.getOnService()
		assert.Equal(t, false, resOnService)
	})

	t.Run("test VectorFieldInfo", func(t *testing.T) {
		fieldID := rowIDFieldID
		info := &VectorFieldInfo{
			fieldBinlog: &datapb.FieldBinlog{
				FieldID: fieldID,
				Binlogs: []*datapb.Binlog{},
			},
		}
		segment.setVectorFieldInfo(fieldID, info)
		resInfo, err := segment.getVectorFieldInfo(fieldID)
		assert.NoError(t, err)
		assert.Equal(t, info, resInfo)

		_, err = segment.getVectorFieldInfo(FieldID(1000))
		assert.Error(t, err)
	})
}

func TestSegment_fillVectorFieldsData(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	schema := genSimpleSegCoreSchema()
	collection := newCollection(defaultCollectionID, schema)
	segment := newSegment(collection,
		defaultSegmentID,
		defaultPartitionID,
		defaultCollectionID,
		defaultDMLChannel,
		segmentTypeSealed,
		true)

	vecCM, err := genVectorChunkManager(ctx)
	assert.NoError(t, err)

	t.Run("test fillVectorFieldsData float-vector invalid vectorChunkManager", func(t *testing.T) {
		fieldID := FieldID(100)
		fieldName := "float-vector-field-0"
		segment.setIndexInfo(fieldID, &indexInfo{})
		info := &VectorFieldInfo{
			fieldBinlog: &datapb.FieldBinlog{
				FieldID: fieldID,
				Binlogs: []*datapb.Binlog{},
			},
		}
		segment.setVectorFieldInfo(fieldID, info)
		fieldData := []*schemapb.FieldData{
			{
				Type:      schemapb.DataType_FloatVector,
				FieldName: fieldName,
				FieldId:   fieldID,
				Field: &schemapb.FieldData_Vectors{
					Vectors: &schemapb.VectorField{
						Dim: defaultDim,
						Data: &schemapb.VectorField_FloatVector{
							FloatVector: &schemapb.FloatArray{
								Data: []float32{1.1, 2.2, 3.3, 4.4},
							},
						},
					},
				},
			},
		}
		result := &segcorepb.RetrieveResults{
			Ids:        &schemapb.IDs{},
			Offset:     []int64{0},
			FieldsData: fieldData,
		}
		err = segment.fillVectorFieldsData(defaultCollectionID, vecCM, result)
		assert.Error(t, err)
	})
}

func TestSegment_indexParam(t *testing.T) {
	schema := genSimpleSegCoreSchema()
	collection := newCollection(defaultCollectionID, schema)
	segment := newSegment(collection,
		defaultSegmentID,
		defaultPartitionID,
		defaultCollectionID,
		defaultDMLChannel,
		segmentTypeSealed,
		true)

	t.Run("test indexParam", func(t *testing.T) {
		fieldID := rowIDFieldID
		iParam := genSimpleIndexParams()
		segment.indexInfos[fieldID] = &indexInfo{}
		err := segment.setIndexParam(fieldID, iParam)
		assert.NoError(t, err)
		_ = segment.getIndexParams(fieldID)
		match := segment.matchIndexParam(fieldID, iParam)
		assert.True(t, match)
		match = segment.matchIndexParam(FieldID(1000), nil)
		assert.False(t, match)
	})
}

func TestSegment_dropFieldData(t *testing.T) {
	t.Run("test dropFieldData", func(t *testing.T) {
		segment, err := genSimpleSealedSegment()
		assert.NoError(t, err)
		segment.setType(segmentTypeIndexing)
		err = segment.dropFieldData(simpleVecField.id)
		assert.NoError(t, err)
	})

	t.Run("test nil segment", func(t *testing.T) {
		segment, err := genSimpleSealedSegment()
		assert.NoError(t, err)
		segment.segmentPtr = nil
		err = segment.dropFieldData(simpleVecField.id)
		assert.Error(t, err)
	})

	t.Run("test invalid segment type", func(t *testing.T) {
		segment, err := genSimpleSealedSegment()
		assert.NoError(t, err)
		err = segment.dropFieldData(simpleVecField.id)
		assert.Error(t, err)
	})

	t.Run("test invalid field", func(t *testing.T) {
		segment, err := genSimpleSealedSegment()
		assert.NoError(t, err)
		segment.setType(segmentTypeIndexing)
		err = segment.dropFieldData(FieldID(1000))
		assert.Error(t, err)
	})
}

func TestSegment_updateSegmentIndex(t *testing.T) {
	t.Run("test updateSegmentIndex invalid", func(t *testing.T) {
		schema := genSimpleSegCoreSchema()
		collection := newCollection(defaultCollectionID, schema)
		segment := newSegment(collection,
			defaultSegmentID,
			defaultPartitionID,
			defaultCollectionID,
			defaultDMLChannel,
			segmentTypeSealed,
			true)

		fieldID := rowIDFieldID
		iParam := genSimpleIndexParams()
		segment.indexInfos[fieldID] = &indexInfo{}
		err := segment.setIndexParam(fieldID, iParam)
		assert.NoError(t, err)

		indexPaths := make([]string, 0)
		indexPaths = append(indexPaths, "IVF")
		err = segment.setIndexPaths(fieldID, indexPaths)
		assert.NoError(t, err)

		indexBytes, err := genIndexBinarySet()
		assert.NoError(t, err)
		err = segment.updateSegmentIndex(indexBytes, fieldID)
		assert.Error(t, err)

		segment.setType(segmentTypeGrowing)
		err = segment.updateSegmentIndex(indexBytes, fieldID)
		assert.Error(t, err)

		segment.setType(segmentTypeSealed)
		segment.segmentPtr = nil
		err = segment.updateSegmentIndex(indexBytes, fieldID)
		assert.Error(t, err)
	})
}

func TestSegment_dropSegmentIndex(t *testing.T) {
	t.Run("test dropSegmentIndex invalid segment type", func(t *testing.T) {
		schema := genSimpleSegCoreSchema()
		collection := newCollection(defaultCollectionID, schema)
		segment := newSegment(collection,
			defaultSegmentID,
			defaultPartitionID,
			defaultCollectionID,
			defaultDMLChannel,
			segmentTypeSealed,
			true)

		fieldID := rowIDFieldID
		err := segment.dropSegmentIndex(fieldID)
		assert.Error(t, err)
	})

	t.Run("test dropSegmentIndex nil segment ptr", func(t *testing.T) {
		schema := genSimpleSegCoreSchema()
		collection := newCollection(defaultCollectionID, schema)
		segment := newSegment(collection,
			defaultSegmentID,
			defaultPartitionID,
			defaultCollectionID,
			defaultDMLChannel,
			segmentTypeSealed,
			true)

		segment.segmentPtr = nil
		fieldID := rowIDFieldID
		err := segment.dropSegmentIndex(fieldID)
		assert.Error(t, err)
	})

	t.Run("test dropSegmentIndex nil index", func(t *testing.T) {
		schema := genSimpleSegCoreSchema()
		collection := newCollection(defaultCollectionID, schema)
		segment := newSegment(collection,
			defaultSegmentID,
			defaultPartitionID,
			defaultCollectionID,
			defaultDMLChannel,
			segmentTypeSealed,
			true)
		segment.setType(segmentTypeIndexing)

		fieldID := rowIDFieldID
		err := segment.dropSegmentIndex(fieldID)
		assert.Error(t, err)
	})
}
