github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/test/testcases/main_test.go (about) 1 package testcases 2 3 import ( 4 "context" 5 "flag" 6 "log" 7 "os" 8 "strconv" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/require" 13 14 "github.com/milvus-io/milvus-sdk-go/v2/client" 15 16 "github.com/milvus-io/milvus-sdk-go/v2/entity" 17 "github.com/milvus-io/milvus-sdk-go/v2/test/base" 18 "github.com/milvus-io/milvus-sdk-go/v2/test/common" 19 ) 20 21 var addr = flag.String("addr", "localhost:19530", "server host and port") 22 23 func init() { 24 log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) 25 } 26 27 // teardown 28 func teardown() { 29 log.Println("Start to tear down all") 30 ctx, cancel := context.WithTimeout(context.Background(), time.Second*common.DefaultTimeout) 31 defer cancel() 32 mc, err := base.NewDefaultMilvusClient(ctx, *addr) 33 if err != nil { 34 log.Fatalf("teardown failed to connect milvus with error %v", err) 35 } 36 defer mc.Close() 37 38 // clear dbs 39 dbs, _ := mc.ListDatabases(ctx) 40 for _, db := range dbs { 41 if db.Name != common.DefaultDb { 42 _ = mc.UsingDatabase(ctx, db.Name) 43 collections, _ := mc.ListCollections(ctx) 44 for _, coll := range collections { 45 _ = mc.DropCollection(ctx, coll.Name) 46 } 47 _ = mc.DropDatabase(ctx, db.Name) 48 } 49 } 50 } 51 52 func createContext(t *testing.T, timeout time.Duration) context.Context { 53 ctx, cancel := context.WithTimeout(context.Background(), timeout) 54 t.Cleanup(func() { 55 cancel() 56 }) 57 return ctx 58 } 59 60 // create connect 61 func createMilvusClient(ctx context.Context, t *testing.T, cfg ...client.Config) *base.MilvusClient { 62 t.Helper() 63 64 var ( 65 mc *base.MilvusClient 66 err error 67 ) 68 if len(cfg) == 0 { 69 mc, err = base.NewDefaultMilvusClient(ctx, *addr) 70 } else { 71 cfg[0].Address = *addr 72 mc, err = base.NewMilvusClient(ctx, cfg[0]) 73 } 74 common.CheckErr(t, err, true) 75 76 t.Cleanup(func() { 77 mc.Close() 78 }) 79 80 return mc 81 } 82 83 // create default collection 84 func createCustomerCollection(ctx context.Context, t *testing.T, mc *base.MilvusClient, schema *entity.Schema, 85 shardsNum int32, opts ...client.CreateCollectionOption) { 86 t.Helper() 87 88 // create default collection with customer schema 89 errCreateCollection := mc.CreateCollection(ctx, schema, shardsNum, opts...) 90 common.CheckErr(t, errCreateCollection, true) 91 92 // close connect and drop collection after each case 93 t.Cleanup(func() { 94 _ = mc.DropCollection(ctx, schema.CollectionName) 95 }) 96 } 97 98 // create default collection 99 func createDefaultCollection(ctx context.Context, t *testing.T, mc *base.MilvusClient, autoID bool, shards int32, opts ...client.CreateCollectionOption) string { 100 t.Helper() 101 102 // prepare schema 103 collName := common.GenRandomString(6) 104 fields := common.GenDefaultFields(autoID) 105 schema := common.GenSchema(collName, autoID, fields) 106 107 // create default collection with fields: [int64, float, floatVector] and vector dim is default 128 108 errCreateCollection := mc.CreateCollection(ctx, schema, shards, opts...) 109 common.CheckErr(t, errCreateCollection, true) 110 111 // close connect and drop collection after each case 112 t.Cleanup(func() { 113 mc.DropCollection(ctx, collName) 114 }) 115 return collName 116 } 117 118 // create default collection 119 func createDefaultBinaryCollection(ctx context.Context, t *testing.T, mc *base.MilvusClient, autoID bool, dim int64) string { 120 t.Helper() 121 122 // prepare schema 123 collName := common.GenRandomString(6) 124 fields := common.GenDefaultBinaryFields(autoID, dim) 125 schema := common.GenSchema(collName, autoID, fields) 126 127 // create default collection with fields: [int64, float, floatVector] and vector dim is default 128 128 errCreateCollection := mc.CreateCollection(ctx, schema, common.DefaultShards) 129 common.CheckErr(t, errCreateCollection, true) 130 131 // close connect and drop collection after each case 132 t.Cleanup(func() { 133 mc.DropCollection(ctx, collName) 134 // mc.Close() 135 }) 136 return collName 137 } 138 139 // create default varchar pk collection 140 func createDefaultVarcharCollection(ctx context.Context, t *testing.T, mc *base.MilvusClient, opts ...client.CreateCollectionOption) string { 141 t.Helper() 142 143 // prepare schema 144 collName := common.GenRandomString(6) 145 fields := common.GenDefaultVarcharFields(false) 146 schema := common.GenSchema(collName, false, fields) 147 148 // create default collection with fields: [int64, float, floatVector] and vector dim is default 128 149 errCreateCollection := mc.CreateCollection(ctx, schema, common.DefaultShards, opts...) 150 common.CheckErr(t, errCreateCollection, true) 151 152 // close connect and drop collection after each case 153 t.Cleanup(func() { 154 mc.DropCollection(ctx, collName) 155 // mc.Close() 156 }) 157 return collName 158 } 159 160 func createCollectionWithDataIndex(ctx context.Context, t *testing.T, mc *base.MilvusClient, autoID bool, withIndex bool, opts ...client.CreateCollectionOption) (string, entity.Column) { 161 // collection 162 collName := createDefaultCollection(ctx, t, mc, autoID, common.DefaultShards, opts...) 163 // insert data 164 var ids entity.Column 165 intColumn, floatColumn, vecColumn := common.GenDefaultColumnData(0, common.DefaultNb, common.DefaultDim) 166 if autoID { 167 pk, errInsert := mc.Insert(ctx, collName, common.DefaultPartition, floatColumn, vecColumn) 168 common.CheckErr(t, errInsert, true) 169 ids = pk 170 } else { 171 pk, errInsert := mc.Insert(ctx, collName, common.DefaultPartition, intColumn, floatColumn, vecColumn) 172 common.CheckErr(t, errInsert, true) 173 common.CheckInsertResult(t, pk, intColumn) 174 ids = pk 175 } 176 177 // flush 178 errFlush := mc.Flush(ctx, collName, false) 179 common.CheckErr(t, errFlush, true) 180 181 // create index 182 if withIndex { 183 idx, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 184 err := mc.CreateIndex(ctx, collName, common.DefaultFloatVecFieldName, idx, false, client.WithIndexName("")) 185 common.CheckErr(t, err, true) 186 } 187 return collName, ids 188 } 189 190 func createBinaryCollectionWithDataIndex(ctx context.Context, t *testing.T, mc *base.MilvusClient, autoID bool, withIndex bool) (string, entity.Column) { 191 // collection 192 collName := createDefaultBinaryCollection(ctx, t, mc, autoID, common.DefaultDim) 193 194 // insert data 195 var ids entity.Column 196 intColumn, floatColumn, vecColumn := common.GenDefaultBinaryData(0, common.DefaultNb, common.DefaultDim) 197 if autoID { 198 pk, errInsert := mc.Insert(ctx, collName, common.DefaultPartition, floatColumn, vecColumn) 199 common.CheckErr(t, errInsert, true) 200 ids = pk 201 } else { 202 pk, errInsert := mc.Insert(ctx, collName, common.DefaultPartition, intColumn, floatColumn, vecColumn) 203 common.CheckErr(t, errInsert, true) 204 common.CheckInsertResult(t, pk, intColumn) 205 ids = pk 206 } 207 208 // flush 209 errFlush := mc.Flush(ctx, collName, false) 210 common.CheckErr(t, errFlush, true) 211 212 // create index 213 if withIndex { 214 idx, _ := entity.NewIndexBinIvfFlat(entity.JACCARD, 128) 215 err := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, idx, false, client.WithIndexName("")) 216 common.CheckErr(t, err, true) 217 } 218 return collName, ids 219 } 220 221 func createVarcharCollectionWithDataIndex(ctx context.Context, t *testing.T, mc *base.MilvusClient, withIndex bool, opts ...client.CreateCollectionOption) (string, entity.Column) { 222 // collection 223 collName := createDefaultVarcharCollection(ctx, t, mc, opts...) 224 225 // insert data 226 varcharColumn, vecColumn := common.GenDefaultVarcharData(0, common.DefaultNb, common.DefaultDim) 227 ids, errInsert := mc.Insert(ctx, collName, common.DefaultPartition, varcharColumn, vecColumn) 228 common.CheckErr(t, errInsert, true) 229 common.CheckInsertResult(t, ids, varcharColumn) 230 231 // flush 232 errFlush := mc.Flush(ctx, collName, false) 233 common.CheckErr(t, errFlush, true) 234 235 // create index 236 if withIndex { 237 idx, _ := entity.NewIndexBinIvfFlat(entity.JACCARD, 128) 238 err := mc.CreateIndex(ctx, collName, common.DefaultBinaryVecFieldName, idx, false, client.WithIndexName("")) 239 common.CheckErr(t, err, true) 240 } 241 return collName, ids 242 } 243 244 const ( 245 Int64FloatVec CollectionFieldsType = "PkInt64FloatVec" // int64 + float + floatVec 246 Int64BinaryVec CollectionFieldsType = "Int64BinaryVec" // int64 + float + binaryVec 247 VarcharBinaryVec CollectionFieldsType = "PkVarcharBinaryVec" // varchar + binaryVec 248 Int64FloatVecJSON CollectionFieldsType = "PkInt64FloatVecJson" // int64 + float + floatVec + json 249 Int64FloatVecArray CollectionFieldsType = "Int64FloatVecArray" // int64 + float + floatVec + all array 250 Int64VarcharSparseVec CollectionFieldsType = "Int64VarcharSparseVec" // int64 + varchar + float32Vec + sparseVec 251 AllVectors CollectionFieldsType = "AllVectors" // int64 + fp32Vec + fp16Vec + bf16Vec + binaryVec 252 AllFields CollectionFieldsType = "AllFields" // all scalar fields + floatVec 253 ) 254 255 func createCollection(ctx context.Context, t *testing.T, mc *base.MilvusClient, cp CollectionParams, opts ...client.CreateCollectionOption) string { 256 collName := common.GenRandomString(4) 257 var fields []*entity.Field 258 // fields 259 switch cp.CollectionFieldsType { 260 // int64 + float + floatVec 261 case Int64FloatVec: 262 fields = common.GenDefaultFields(cp.AutoID) 263 // int64 + float + binaryVec 264 case Int64BinaryVec: 265 fields = common.GenDefaultBinaryFields(cp.AutoID, cp.Dim) 266 case VarcharBinaryVec: 267 fields = common.GenDefaultVarcharFields(cp.AutoID) 268 case Int64FloatVecJSON: 269 fields = common.GenDefaultFields(cp.AutoID) 270 jsonField := common.GenField(common.DefaultJSONFieldName, entity.FieldTypeJSON) 271 fields = append(fields, jsonField) 272 case Int64FloatVecArray: 273 fields = common.GenDefaultFields(cp.AutoID) 274 fields = append(fields, common.GenAllArrayFieldsWithCapacity(cp.MaxCapacity)...) 275 case Int64VarcharSparseVec: 276 fields = []*entity.Field{ 277 common.GenField(common.DefaultIntFieldName, entity.FieldTypeInt64, common.WithIsPrimaryKey(true), common.WithAutoID(cp.AutoID)), 278 common.GenField(common.DefaultVarcharFieldName, entity.FieldTypeVarChar, common.WithMaxLength(cp.MaxLength)), 279 common.GenField(common.DefaultFloatVecFieldName, entity.FieldTypeFloatVector, common.WithDim(cp.Dim)), 280 common.GenField(common.DefaultSparseVecFieldName, entity.FieldTypeSparseVector), 281 } 282 283 case AllVectors: 284 fields = []*entity.Field{ 285 common.GenField(common.DefaultIntFieldName, entity.FieldTypeInt64, common.WithIsPrimaryKey(true), common.WithAutoID(cp.AutoID)), 286 common.GenField(common.DefaultFloatVecFieldName, entity.FieldTypeFloatVector, common.WithDim(cp.Dim)), 287 common.GenField(common.DefaultFloat16VecFieldName, entity.FieldTypeFloat16Vector, common.WithDim(cp.Dim)), 288 common.GenField(common.DefaultBFloat16VecFieldName, entity.FieldTypeBFloat16Vector, common.WithDim(cp.Dim)), 289 common.GenField(common.DefaultBinaryVecFieldName, entity.FieldTypeBinaryVector, common.WithDim(cp.Dim)), 290 } 291 case AllFields: 292 fields = common.GenAllFields() 293 } 294 295 // schema 296 schema := common.GenSchema(collName, cp.AutoID, fields, common.WithEnableDynamicField(cp.EnableDynamicField)) 297 298 // create collection 299 err := mc.CreateCollection(ctx, schema, cp.ShardsNum, opts...) 300 common.CheckErr(t, err, true) 301 302 t.Cleanup(func() { 303 _ = mc.DropCollection(ctx, collName) 304 }) 305 306 return collName 307 } 308 309 func insertData(ctx context.Context, t *testing.T, mc *base.MilvusClient, dp DataParams, opts ...common.GenColumnDataOption) (entity.Column, error) { 310 // todo autoid 311 // prepare data 312 var data []entity.Column 313 rows := make([]interface{}, 0, dp.nb) 314 switch dp.CollectionFieldsType { 315 316 // int64 + float + floatVec 317 case Int64FloatVec: 318 if dp.WithRows { 319 rows = common.GenDefaultRows(dp.start, dp.nb, dp.dim, dp.EnableDynamicField) 320 } else { 321 intColumn, floatColumn, vecColumn := common.GenDefaultColumnData(dp.start, dp.nb, dp.dim) 322 data = append(data, intColumn, floatColumn, vecColumn) 323 } 324 325 // int64 + float + binaryVec 326 case Int64BinaryVec: 327 if dp.WithRows { 328 rows = common.GenDefaultBinaryRows(dp.start, dp.nb, dp.dim, dp.EnableDynamicField) 329 } else { 330 intColumn, floatColumn, binaryColumn := common.GenDefaultBinaryData(dp.start, dp.nb, dp.dim) 331 data = append(data, intColumn, floatColumn, binaryColumn) 332 } 333 // varchar + binary 334 case VarcharBinaryVec: 335 if dp.WithRows { 336 rows = common.GenDefaultVarcharRows(dp.start, dp.nb, dp.dim, dp.EnableDynamicField) 337 } else { 338 varcharColumn, binaryColumn := common.GenDefaultVarcharData(dp.start, dp.nb, dp.dim) 339 data = append(data, varcharColumn, binaryColumn) 340 } 341 342 // default + json 343 case Int64FloatVecJSON: 344 if dp.WithRows { 345 rows = common.GenDefaultJSONRows(dp.start, dp.nb, dp.dim, dp.EnableDynamicField) 346 } else { 347 intColumn, floatColumn, vecColumn := common.GenDefaultColumnData(dp.start, dp.nb, dp.dim) 348 jsonColumn := common.GenDefaultJSONData(common.DefaultJSONFieldName, dp.start, dp.nb) 349 data = append(data, intColumn, floatColumn, vecColumn, jsonColumn) 350 } 351 case Int64FloatVecArray: 352 if dp.WithRows { 353 rows = common.GenDefaultArrayRows(dp.start, dp.nb, dp.dim, dp.EnableDynamicField) 354 } else { 355 data = common.GenAllArrayData(dp.start, dp.nb, opts...) 356 intColumn, floatColumn, vecColumn := common.GenDefaultColumnData(dp.start, dp.nb, dp.dim) 357 data = append(data, intColumn, floatColumn, vecColumn) 358 } 359 case Int64VarcharSparseVec: 360 if dp.WithRows { 361 rows = common.GenDefaultSparseRows(dp.start, dp.nb, dp.dim, dp.maxLenSparse, dp.EnableDynamicField) 362 } else { 363 intColumn, _, vecColumn := common.GenDefaultColumnData(dp.start, dp.nb, dp.dim) 364 varColumn := common.GenColumnData(dp.start, dp.nb, entity.FieldTypeVarChar, common.DefaultVarcharFieldName) 365 sparseColumn := common.GenColumnData(dp.start, dp.nb, entity.FieldTypeSparseVector, common.DefaultSparseVecFieldName, opts...) 366 data = append(data, intColumn, varColumn, vecColumn, sparseColumn) 367 } 368 case AllVectors: 369 if dp.WithRows { 370 rows = common.GenAllVectorsRows(dp.start, dp.nb, dp.dim, dp.EnableDynamicField) 371 } 372 data = common.GenAllVectorsData(dp.start, dp.nb, dp.dim, opts...) 373 case AllFields: 374 if dp.WithRows { 375 rows = common.GenAllFieldsRows(dp.start, dp.nb, dp.dim, dp.EnableDynamicField, opts...) 376 } 377 data = common.GenAllFieldsData(dp.start, dp.nb, dp.dim, opts...) 378 } 379 380 if dp.EnableDynamicField && !dp.WithRows { 381 data = append(data, common.GenDynamicFieldData(dp.start, dp.nb)...) 382 } 383 384 // insert 385 var ids entity.Column 386 var err error 387 if dp.WithRows { 388 ids, err = mc.InsertRows(ctx, dp.CollectionName, dp.PartitionName, rows) 389 } else { 390 ids, err = mc.Insert(ctx, dp.CollectionName, dp.PartitionName, data...) 391 } 392 common.CheckErr(t, err, true) 393 require.Equalf(t, dp.nb, ids.Len(), "Expected insert id num: %d, actual: ", dp.nb, ids.Len()) 394 return ids, err 395 } 396 397 // create collection with all scala fields and insert data without flush 398 func createCollectionAllFields(ctx context.Context, t *testing.T, mc *base.MilvusClient, nb int, start int) (string, entity.Column) { 399 t.Helper() 400 401 // prepare fields, name, schema 402 allFields := common.GenAllFields() 403 collName := common.GenRandomString(6) 404 schema := common.GenSchema(collName, false, allFields) 405 406 // create collection 407 errCreateCollection := mc.CreateCollection(ctx, schema, common.DefaultShards) 408 common.CheckErr(t, errCreateCollection, true) 409 410 data := common.GenAllFieldsData(start, nb, common.DefaultDim, common.WithArrayCapacity(common.TestCapacity)) 411 ids, errInsert := mc.Insert(ctx, collName, "", data...) 412 common.CheckErr(t, errInsert, true) 413 require.Equal(t, nb, ids.Len()) 414 return collName, ids 415 } 416 417 func createInsertTwoPartitions(ctx context.Context, t *testing.T, mc *base.MilvusClient, collName string, nb int) (partitionName string, defaultPartition HelpPartitionColumns, newPartition HelpPartitionColumns) { 418 // create new partition 419 partitionName = "new" 420 _ = mc.CreatePartition(ctx, collName, partitionName) 421 422 // insert nb into default partition, pks from 0 to nb 423 intColumn, floatColumn, vecColumn := common.GenDefaultColumnData(0, nb, common.DefaultDim) 424 idsDefault, _ := mc.Insert(ctx, collName, common.DefaultPartition, intColumn, floatColumn, vecColumn) 425 426 // insert nb into new partition, pks from nb to nb*2 427 intColumnNew, floatColumnNew, vecColumnNew := common.GenDefaultColumnData(nb, nb, common.DefaultDim) 428 idsPartition, _ := mc.Insert(ctx, collName, partitionName, intColumnNew, floatColumnNew, vecColumnNew) 429 430 // flush 431 errFlush := mc.Flush(ctx, collName, false) 432 common.CheckErr(t, errFlush, true) 433 stats, _ := mc.GetCollectionStatistics(ctx, collName) 434 require.Equal(t, strconv.Itoa(nb*2), stats[common.RowCount]) 435 436 defaultPartition = HelpPartitionColumns{ 437 PartitionName: common.DefaultPartition, 438 IdsColumn: idsDefault, 439 VectorColumn: vecColumn, 440 } 441 442 newPartition = HelpPartitionColumns{ 443 PartitionName: partitionName, 444 IdsColumn: idsPartition, 445 VectorColumn: vecColumnNew, 446 } 447 448 return partitionName, defaultPartition, newPartition 449 } 450 451 // prepare collection, maybe data index and load 452 func prepareCollection(ctx context.Context, t *testing.T, mc *base.MilvusClient, collParam CollectionParams, opts ...PrepareCollectionOption) string { 453 // default insert nb entities with 0 start 454 defaultDp := DataParams{DoInsert: true, CollectionName: "", PartitionName: "", CollectionFieldsType: collParam.CollectionFieldsType, 455 start: 0, nb: common.DefaultNb, dim: collParam.Dim, EnableDynamicField: collParam.EnableDynamicField, WithRows: false} 456 457 // default do flush 458 defaultFp := FlushParams{DoFlush: true, PartitionNames: []string{}, async: false} 459 460 // default build index 461 idx, err := entity.NewIndexHNSW(entity.L2, 8, 96) 462 common.CheckErr(t, err, true) 463 defaultIndexParams := []IndexParams{{BuildIndex: true, Index: idx, FieldName: common.DefaultFloatVecFieldName, async: false}} 464 465 // default load collection 466 defaultLp := LoadParams{DoLoad: true, async: false} 467 opt := &ClientParamsOption{ 468 DataParams: defaultDp, 469 FlushParams: defaultFp, 470 IndexParams: defaultIndexParams, 471 LoadParams: defaultLp, 472 } 473 for _, o := range opts { 474 o(opt) 475 } 476 // create collection 477 collName := createCollection(ctx, t, mc, collParam, opt.CreateOpts) 478 479 // insert 480 if opt.DataParams.DoInsert { 481 if opt.DataParams.EnableDynamicField != collParam.EnableDynamicField { 482 t.Fatalf("The EnableDynamicField of CollectionParams and DataParams should be equal.") 483 } 484 opt.DataParams.CollectionName = collName 485 opt.DataParams.CollectionFieldsType = collParam.CollectionFieldsType 486 insertData(ctx, t, mc, opt.DataParams) 487 } 488 489 // flush 490 if opt.FlushParams.DoFlush { 491 err := mc.Flush(ctx, collName, opt.FlushParams.async) 492 common.CheckErr(t, err, true) 493 } 494 495 // index 496 for _, idxParams := range opt.IndexParams { 497 if idxParams.BuildIndex { 498 var err error 499 if opt.IndexOpts == nil { 500 err = mc.CreateIndex(ctx, collName, idxParams.FieldName, idxParams.Index, idxParams.async) 501 } else { 502 err = mc.CreateIndex(ctx, collName, idxParams.FieldName, idxParams.Index, idxParams.async, opt.IndexOpts) 503 } 504 common.CheckErr(t, err, true) 505 } 506 } 507 508 // load 509 if opt.LoadParams.DoLoad { 510 var err error 511 if len(opt.LoadParams.PartitionNames) > 0 { 512 err = mc.LoadPartitions(ctx, collName, opt.LoadParams.PartitionNames, opt.LoadParams.async) 513 common.CheckErr(t, err, true) 514 } else { 515 if opt.LoadOpts != nil { 516 err = mc.LoadCollection(ctx, collName, opt.LoadParams.async, opt.LoadOpts) 517 } else { 518 err = mc.LoadCollection(ctx, collName, opt.LoadParams.async) 519 } 520 common.CheckErr(t, err, true) 521 } 522 } 523 return collName 524 } 525 526 func GenDefaultIndexParamsForAllVectors() []IndexParams { 527 indexHnsw, _ := entity.NewIndexHNSW(entity.L2, 8, 96) 528 indexBinary, _ := entity.NewIndexBinIvfFlat(entity.JACCARD, 64) 529 ips := make([]IndexParams, 4) 530 for _, fieldName := range common.AllVectorsFieldsName { 531 if fieldName == common.DefaultBinaryVecFieldName { 532 ips = append(ips, IndexParams{BuildIndex: true, Index: indexBinary, FieldName: fieldName, async: false}) 533 } else { 534 ips = append(ips, IndexParams{BuildIndex: true, Index: indexHnsw, FieldName: fieldName, async: false}) 535 } 536 } 537 return ips 538 } 539 540 func TestMain(m *testing.M) { 541 flag.Parse() 542 log.Printf("parse addr=%s", *addr) 543 code := m.Run() 544 teardown() 545 os.Exit(code) 546 }