@@ -1353,6 +1353,130 @@ func (suite *APIsTestSuite) TestCollectionVersioningWithMinio() {
1353
1353
// suite.True(exists, "Version file should exist in S3")
1354
1354
}
1355
1355
1356
+ func (suite * APIsTestSuite ) TestForkCollection () {
1357
+ ctx := context .Background ()
1358
+
1359
+ sourceCreateCollection := & model.CreateCollection {
1360
+ ID : types .NewUniqueID (),
1361
+ Name : "test_fork_collection_source" ,
1362
+ TenantID : suite .tenantName ,
1363
+ DatabaseName : suite .databaseName ,
1364
+ }
1365
+
1366
+ sourceCreateMetadataSegment := & model.CreateSegment {
1367
+ ID : types .NewUniqueID (),
1368
+ Type : "test_blockfile" ,
1369
+ Scope : "METADATA" ,
1370
+ CollectionID : sourceCreateCollection .ID ,
1371
+ }
1372
+
1373
+ sourceCreateRecordSegment := & model.CreateSegment {
1374
+ ID : types .NewUniqueID (),
1375
+ Type : "test_blockfile" ,
1376
+ Scope : "RECORD" ,
1377
+ CollectionID : sourceCreateCollection .ID ,
1378
+ }
1379
+
1380
+ sourceCreateVectorSegment := & model.CreateSegment {
1381
+ ID : types .NewUniqueID (),
1382
+ Type : "test_hnsw" ,
1383
+ Scope : "VECTOR" ,
1384
+ CollectionID : sourceCreateCollection .ID ,
1385
+ }
1386
+
1387
+ segments := []* model.CreateSegment {
1388
+ sourceCreateMetadataSegment ,
1389
+ sourceCreateRecordSegment ,
1390
+ sourceCreateVectorSegment ,
1391
+ }
1392
+
1393
+ // Create source collection
1394
+ _ , _ , err := suite .coordinator .CreateCollectionAndSegments (ctx , sourceCreateCollection , segments )
1395
+ suite .NoError (err )
1396
+
1397
+ sourceFlushMetadataSegment := & model.FlushSegmentCompaction {
1398
+ ID : sourceCreateMetadataSegment .ID ,
1399
+ FilePaths : map [string ][]string {
1400
+ "fts_index" : {"metadata_sparse_index_file" },
1401
+ },
1402
+ }
1403
+
1404
+ sourceFlushRecordSegment := & model.FlushSegmentCompaction {
1405
+ ID : sourceCreateRecordSegment .ID ,
1406
+ FilePaths : map [string ][]string {
1407
+ "data_record" : {"record_sparse_index_file" },
1408
+ },
1409
+ }
1410
+
1411
+ sourceFlushVectorSegment := & model.FlushSegmentCompaction {
1412
+ ID : sourceCreateVectorSegment .ID ,
1413
+ FilePaths : map [string ][]string {
1414
+ "hnsw_index" : {"hnsw_source_layer_file" },
1415
+ },
1416
+ }
1417
+
1418
+ sourceFlushCollectionCompaction := & model.FlushCollectionCompaction {
1419
+ ID : sourceCreateCollection .ID ,
1420
+ TenantID : sourceCreateCollection .TenantID ,
1421
+ LogPosition : 1000 ,
1422
+ CurrentCollectionVersion : 0 ,
1423
+ FlushSegmentCompactions : []* model.FlushSegmentCompaction {
1424
+ sourceFlushMetadataSegment ,
1425
+ sourceFlushRecordSegment ,
1426
+ sourceFlushVectorSegment ,
1427
+ },
1428
+ TotalRecordsPostCompaction : 1000 ,
1429
+ SizeBytesPostCompaction : 65536 ,
1430
+ }
1431
+
1432
+ // Flush some data to sourceo collection
1433
+ _ , err = suite .coordinator .FlushCollectionCompaction (ctx , sourceFlushCollectionCompaction )
1434
+ suite .NoError (err )
1435
+
1436
+ // Fork source collection
1437
+ forkCollection := & model.ForkCollection {
1438
+ SourceCollectionID : sourceCreateCollection .ID ,
1439
+ TargetCollectionID : types .NewUniqueID (),
1440
+ TargetCollectionName : "test_fork_collection_fork_1" ,
1441
+ }
1442
+
1443
+ collection , collection_segments , err := suite .coordinator .ForkCollection (ctx , forkCollection )
1444
+ suite .NoError (err )
1445
+ suite .Equal (forkCollection .TargetCollectionID , collection .ID )
1446
+ suite .Equal (forkCollection .TargetCollectionName , collection .Name )
1447
+ suite .Equal (sourceCreateCollection .ID , collection .RootCollectionID )
1448
+ suite .Equal (sourceFlushCollectionCompaction .LogPosition , collection .LogPosition )
1449
+ suite .Equal (sourceFlushCollectionCompaction .TotalRecordsPostCompaction , collection .TotalRecordsPostCompaction )
1450
+ suite .Equal (sourceFlushCollectionCompaction .SizeBytesPostCompaction , collection .SizeBytesPostCompaction )
1451
+ for _ , segment := range collection_segments {
1452
+ suite .Equal (collection .ID , segment .CollectionID )
1453
+ if segment .Scope == "METADATA" {
1454
+ suite .NotEqual (sourceCreateMetadataSegment .ID , segment .ID )
1455
+ suite .Equal (sourceFlushMetadataSegment .FilePaths , segment .FilePaths )
1456
+ } else if segment .Scope == "RECORD" {
1457
+ suite .NotEqual (sourceCreateRecordSegment .ID , segment .ID )
1458
+ suite .Equal (sourceFlushRecordSegment .FilePaths , segment .FilePaths )
1459
+ } else if segment .Scope == "VECTOR" {
1460
+ suite .NotEqual (sourceCreateVectorSegment .ID , segment .ID )
1461
+ suite .Equal (sourceFlushVectorSegment .FilePaths , segment .FilePaths )
1462
+ }
1463
+ }
1464
+
1465
+ // Attempt to fork a collcetion with same name (should fail)
1466
+ forkCollectionWithSameName := & model.ForkCollection {
1467
+ SourceCollectionID : sourceCreateCollection .ID ,
1468
+ TargetCollectionID : types .NewUniqueID (),
1469
+ TargetCollectionName : "test_fork_collection_source" ,
1470
+ }
1471
+ _ , _ , err = suite .coordinator .ForkCollection (ctx , forkCollectionWithSameName )
1472
+ suite .Error (err )
1473
+
1474
+ // Check that the collection was not created
1475
+ collections , err := suite .coordinator .GetCollections (ctx , forkCollectionWithSameName .TargetCollectionID , nil , suite .tenantName , suite .databaseName , nil , nil )
1476
+ suite .NoError (err )
1477
+ suite .Empty (collections )
1478
+ }
1479
+
1356
1480
func TestAPIsTestSuite (t * testing.T ) {
1357
1481
testSuite := new (APIsTestSuite )
1358
1482
suite .Run (t , testSuite )
0 commit comments