github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/test/testcases/resource_group_test.go (about)

     1  //go:build L3
     2  
     3  package testcases
     4  
     5  import (
     6  	"context"
     7  	"log"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/milvus-io/milvus-sdk-go/v2/client"
    12  
    13  	"github.com/milvus-io/milvus-sdk-go/v2/test/base"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/milvus-io/milvus-sdk-go/v2/entity"
    17  
    18  	"github.com/milvus-io/milvus-sdk-go/v2/test/common"
    19  )
    20  
    21  const configQnNodes = int32(4)
    22  const newRgNode = int32(2)
    23  
    24  func resetRgs(t *testing.T, ctx context.Context, mc *base.MilvusClient) {
    25  	// release and drop all collections
    26  	collections, _ := mc.ListCollections(ctx)
    27  	for _, coll := range collections {
    28  		mc.ReleaseCollection(ctx, coll.Name)
    29  		err := mc.DropCollection(ctx, coll.Name)
    30  		common.CheckErr(t, err, true)
    31  	}
    32  
    33  	// reset resource groups
    34  	rgs, errList := mc.ListResourceGroups(ctx)
    35  	common.CheckErr(t, errList, true)
    36  	for _, rg := range rgs {
    37  		if rg != common.DefaultRgName {
    38  			// describe rg and get available node
    39  			rgInfo, errDescribe := mc.DescribeResourceGroup(ctx, rg)
    40  			common.CheckErr(t, errDescribe, true)
    41  
    42  			// transfer available nodes into default rg
    43  			if rgInfo.AvailableNodesNumber > 0 {
    44  				errTransfer := mc.TransferNode(ctx, rg, common.DefaultRgName, rgInfo.AvailableNodesNumber)
    45  				common.CheckErr(t, errTransfer, true)
    46  			}
    47  
    48  			// drop rg
    49  			errDrop := mc.DropResourceGroup(ctx, rg)
    50  			common.CheckErr(t, errDrop, true)
    51  		}
    52  	}
    53  
    54  	rgs2, errList2 := mc.ListResourceGroups(ctx)
    55  	common.CheckErr(t, errList2, true)
    56  	require.Len(t, rgs2, 1)
    57  }
    58  
    59  // test rg default: list rg, create rg, describe rg, transfer node
    60  func TestRgDefault(t *testing.T) {
    61  	ctx := createContext(t, time.Second*common.DefaultTimeout)
    62  	// connect
    63  	mc := createMilvusClient(ctx, t)
    64  	resetRgs(t, ctx, mc)
    65  
    66  	// describe default rg and check default rg info
    67  	defaultRg, errDescribe := mc.DescribeResourceGroup(ctx, common.DefaultRgName)
    68  	common.CheckErr(t, errDescribe, true)
    69  	expDefaultRg := &entity.ResourceGroup{
    70  		Name:                 common.DefaultRgName,
    71  		Capacity:             common.DefaultRgCapacity,
    72  		AvailableNodesNumber: configQnNodes,
    73  	}
    74  	common.CheckResourceGroup(t, defaultRg, expDefaultRg)
    75  
    76  	// create new rg
    77  	rgName := common.GenRandomString(6)
    78  	errCreate := mc.CreateResourceGroup(ctx, rgName)
    79  	common.CheckErr(t, errCreate, true)
    80  
    81  	// list rgs
    82  	rgs, errList := mc.ListResourceGroups(ctx)
    83  	common.CheckErr(t, errList, true)
    84  	require.ElementsMatch(t, rgs, []string{common.DefaultRgName, rgName})
    85  
    86  	// describe new rg and check new rg info
    87  	myRg, errDescribe2 := mc.DescribeResourceGroup(ctx, rgName)
    88  	common.CheckErr(t, errDescribe2, true)
    89  	expRg := &entity.ResourceGroup{
    90  		Name:                 rgName,
    91  		Capacity:             0,
    92  		AvailableNodesNumber: 0,
    93  	}
    94  	common.CheckResourceGroup(t, myRg, expRg)
    95  
    96  	// transfer node from default rg into new rg
    97  	errTransfer := mc.TransferNode(ctx, common.DefaultRgName, rgName, newRgNode)
    98  	common.CheckErr(t, errTransfer, true)
    99  
   100  	// check rg info after transfer nodes
   101  	myRg2, _ := mc.DescribeResourceGroup(ctx, rgName)
   102  	transferRg := &entity.ResourceGroup{
   103  		Name:                 rgName,
   104  		Capacity:             newRgNode,
   105  		AvailableNodesNumber: newRgNode,
   106  	}
   107  	common.CheckResourceGroup(t, myRg2, transferRg)
   108  
   109  	// check default rg info
   110  	defaultRg2, _ := mc.DescribeResourceGroup(ctx, common.DefaultRgName)
   111  	expDefaultRg2 := &entity.ResourceGroup{
   112  		Name:                 common.DefaultRgName,
   113  		Capacity:             common.DefaultRgCapacity,
   114  		AvailableNodesNumber: configQnNodes - newRgNode,
   115  	}
   116  	common.CheckResourceGroup(t, defaultRg2, expDefaultRg2)
   117  
   118  	// try to drop default rg
   119  	errDropDefault := mc.DropResourceGroup(ctx, common.DefaultRgName)
   120  	common.CheckErr(t, errDropDefault, false, "default resource group is not deletable")
   121  }
   122  
   123  // test create rg with invalid name
   124  func TestCreateRgInvalidNames(t *testing.T) {
   125  	t.Parallel()
   126  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   127  	// connect
   128  	mc := createMilvusClient(ctx, t)
   129  
   130  	type invalidNameStruct struct {
   131  		name   string
   132  		errMsg string
   133  	}
   134  
   135  	invalidNames := []invalidNameStruct{
   136  		{name: "", errMsg: "resource group name couldn't be empty"},
   137  		{name: "12-s", errMsg: "name must be an underscore or letter"},
   138  		{name: "(mn)", errMsg: "name must be an underscore or letter"},
   139  		{name: "中文", errMsg: "name must be an underscore or letter"},
   140  		{name: "%$#", errMsg: "name must be an underscore or letter"},
   141  		{name: common.GenLongString(common.MaxCollectionNameLen + 1), errMsg: "name must be less than 255 characters"},
   142  	}
   143  	// create rg with invalid name
   144  	for _, invalidName := range invalidNames {
   145  		errCreate := mc.CreateResourceGroup(ctx, invalidName.name)
   146  		common.CheckErr(t, errCreate, false, invalidName.errMsg)
   147  	}
   148  }
   149  
   150  // describe rg with not existed name
   151  func TestDescribeRgNotExisted(t *testing.T) {
   152  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   153  	// connect
   154  	mc := createMilvusClient(ctx, t)
   155  
   156  	_, errDescribe := mc.DescribeResourceGroup(ctx, common.GenRandomString(6))
   157  	common.CheckErr(t, errDescribe, false, "resource group not found")
   158  }
   159  
   160  // drop rg with not existed name -> successfully
   161  func TestDropRgNotExisted(t *testing.T) {
   162  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   163  	// connect
   164  	mc := createMilvusClient(ctx, t)
   165  
   166  	errDrop := mc.DropResourceGroup(ctx, common.GenRandomString(6))
   167  	common.CheckErr(t, errDrop, true)
   168  }
   169  
   170  // drop rg
   171  func TestDropRgNonEmpty(t *testing.T) {
   172  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   173  	// connect
   174  	mc := createMilvusClient(ctx, t)
   175  	resetRgs(t, ctx, mc)
   176  
   177  	// create new rg
   178  	rgName := common.GenRandomString(6)
   179  	errCreate := mc.CreateResourceGroup(ctx, rgName)
   180  	common.CheckErr(t, errCreate, true)
   181  
   182  	// transfer node
   183  	errTransfer := mc.TransferNode(ctx, common.DefaultRgName, rgName, 1)
   184  	common.CheckErr(t, errTransfer, true)
   185  
   186  	// drop rg and rg available node is not 0
   187  	errDrop := mc.DropResourceGroup(ctx, rgName)
   188  	common.CheckErr(t, errDrop, false, "resource group's limits node num is not 0")
   189  }
   190  
   191  // drop empty default rg
   192  func TestDropEmptyRg(t *testing.T) {
   193  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   194  	// connect
   195  	mc := createMilvusClient(ctx, t)
   196  	resetRgs(t, ctx, mc)
   197  
   198  	// create new rg
   199  	rgName := common.GenRandomString(6)
   200  	errCreate := mc.CreateResourceGroup(ctx, rgName)
   201  	common.CheckErr(t, errCreate, true)
   202  
   203  	// transfer node
   204  	errTransfer := mc.TransferNode(ctx, common.DefaultRgName, rgName, configQnNodes)
   205  	common.CheckErr(t, errTransfer, true)
   206  
   207  	// describe default rg
   208  	defaultRg, errDescribe := mc.DescribeResourceGroup(ctx, common.DefaultRgName)
   209  	common.CheckErr(t, errDescribe, true)
   210  	transferRg := &entity.ResourceGroup{
   211  		Name:                 common.DefaultRgName,
   212  		Capacity:             common.DefaultRgCapacity,
   213  		AvailableNodesNumber: 0,
   214  	}
   215  	common.CheckResourceGroup(t, defaultRg, transferRg)
   216  
   217  	// drop empty default rg
   218  	errDrop := mc.DropResourceGroup(ctx, common.DefaultRgName)
   219  	common.CheckErr(t, errDrop, false, "default resource group is not deletable")
   220  }
   221  
   222  // test list rgs
   223  func TestListRgs(t *testing.T) {
   224  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   225  	// connect
   226  	mc := createMilvusClient(ctx, t)
   227  	resetRgs(t, ctx, mc)
   228  
   229  	// create 10 new rgs
   230  	rgNum := 10
   231  	rgs := make([]string, 0, rgNum)
   232  	for i := 1; i <= rgNum; i++ {
   233  		rgName := common.GenRandomString(6)
   234  		errCreate := mc.CreateResourceGroup(ctx, rgName)
   235  		common.CheckErr(t, errCreate, true)
   236  		rgs = append(rgs, rgName)
   237  	}
   238  
   239  	// list rgs
   240  	listRgs, errList := mc.ListResourceGroups(ctx)
   241  	common.CheckErr(t, errList, true)
   242  
   243  	rgs = append(rgs, common.DefaultRgName)
   244  	require.ElementsMatch(t, listRgs, rgs)
   245  }
   246  
   247  // test transfer node invalid number
   248  func TestTransferInvalidNodes(t *testing.T) {
   249  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   250  	// connect
   251  	mc := createMilvusClient(ctx, t)
   252  	resetRgs(t, ctx, mc)
   253  
   254  	// create new rg
   255  	rgName := common.GenRandomString(6)
   256  	errCreate := mc.CreateResourceGroup(ctx, rgName)
   257  	common.CheckErr(t, errCreate, true)
   258  	type invalidNodesStruct struct {
   259  		nodesNum int32
   260  		errMsg   string
   261  	}
   262  	invalidNodes := []invalidNodesStruct{
   263  		{nodesNum: 0, errMsg: "invalid parameter[expected=NumNode > 0][actual=invalid NumNode 0]"},
   264  		{nodesNum: -1, errMsg: "invalid parameter[expected=NumNode > 0][actual=invalid NumNode -1]"},
   265  		{nodesNum: 99, errMsg: "resource group node not enough"},
   266  	}
   267  	// transfer node
   268  	for _, invalidNode := range invalidNodes {
   269  		errTransfer := mc.TransferNode(ctx, common.DefaultRgName, rgName, invalidNode.nodesNum)
   270  		common.CheckErr(t, errTransfer, false, invalidNode.errMsg)
   271  	}
   272  }
   273  
   274  // test transfer node rg not exist
   275  func TestTransferRgNotExisted(t *testing.T) {
   276  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   277  	// connect
   278  	mc := createMilvusClient(ctx, t)
   279  	resetRgs(t, ctx, mc)
   280  
   281  	// source not exist
   282  	errSource := mc.TransferNode(ctx, common.GenRandomString(6), common.DefaultRgName, newRgNode)
   283  	common.CheckErr(t, errSource, false, "resource group not found")
   284  
   285  	// target not exist
   286  	errTarget := mc.TransferNode(ctx, common.DefaultRgName, common.GenRandomString(6), newRgNode)
   287  	common.CheckErr(t, errTarget, false, "resource group not found")
   288  
   289  	// transfer to self
   290  	errSelf := mc.TransferNode(ctx, common.DefaultRgName, common.DefaultRgName, newRgNode)
   291  	common.CheckErr(t, errSelf, false, "source resource group and target resource group should not be the same")
   292  
   293  	defaultRg, _ := mc.DescribeResourceGroup(ctx, common.DefaultRgName)
   294  	require.Equal(t, configQnNodes, defaultRg.AvailableNodesNumber)
   295  }
   296  
   297  // test transfer 2 replica2 from default to new rg
   298  func TestTransferReplicas(t *testing.T) {
   299  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   300  	// connect
   301  	mc := createMilvusClient(ctx, t)
   302  	resetRgs(t, ctx, mc)
   303  
   304  	// create new rg
   305  	rgName := common.GenRandomString(6)
   306  	errCreate := mc.CreateResourceGroup(ctx, rgName)
   307  	common.CheckErr(t, errCreate, true)
   308  
   309  	// transfer nodes into new rg
   310  	errTransfer := mc.TransferNode(ctx, common.DefaultRgName, rgName, newRgNode)
   311  	common.CheckErr(t, errTransfer, true)
   312  
   313  	// load two replicas
   314  	collName, _ := createCollectionWithDataIndex(ctx, t, mc, true, true)
   315  
   316  	// load two replicas into default rg
   317  	errLoad := mc.LoadCollection(ctx, collName, false, client.WithReplicaNumber(2), client.WithResourceGroups([]string{common.DefaultRgName}))
   318  	common.CheckErr(t, errLoad, true)
   319  	defaultRg, errDescribe := mc.DescribeResourceGroup(ctx, common.DefaultRgName)
   320  	common.CheckErr(t, errDescribe, true)
   321  	transferRg := &entity.ResourceGroup{
   322  		Name:                 common.DefaultRgName,
   323  		Capacity:             common.DefaultRgCapacity,
   324  		AvailableNodesNumber: configQnNodes - newRgNode,
   325  		LoadedReplica:        map[string]int32{collName: 2},
   326  	}
   327  	common.CheckResourceGroup(t, defaultRg, transferRg)
   328  
   329  	// transfer replica into new rg
   330  	errReplica := mc.TransferReplica(ctx, common.DefaultRgName, rgName, collName, 2)
   331  	common.CheckErr(t, errReplica, true)
   332  
   333  	// check default rg
   334  	defaultRg2, _ := mc.DescribeResourceGroup(ctx, common.DefaultRgName)
   335  	transferRg2 := &entity.ResourceGroup{
   336  		Name:                 common.DefaultRgName,
   337  		Capacity:             common.DefaultRgCapacity,
   338  		AvailableNodesNumber: configQnNodes - newRgNode,
   339  		IncomingNodeNum:      map[string]int32{collName: 2},
   340  	}
   341  	common.CheckResourceGroup(t, defaultRg2, transferRg2)
   342  
   343  	// check new rg after transfer replica
   344  	newRg, _ := mc.DescribeResourceGroup(ctx, rgName)
   345  	expRg := &entity.ResourceGroup{
   346  		Name:                 rgName,
   347  		Capacity:             newRgNode,
   348  		AvailableNodesNumber: newRgNode,
   349  		LoadedReplica:        map[string]int32{collName: 2},
   350  		OutgoingNodeNum:      map[string]int32{collName: 2},
   351  	}
   352  	common.CheckResourceGroup(t, newRg, expRg)
   353  
   354  	// drop new rg that loaded collection
   355  	err := mc.DropResourceGroup(ctx, rgName)
   356  	common.CheckErr(t, err, false, "some replicas still loaded in resource group")
   357  
   358  	// search
   359  	sp, err := entity.NewIndexHNSWSearchParam(74)
   360  	searchRes, _ := mc.Search(
   361  		ctx, collName,
   362  		[]string{common.DefaultPartition},
   363  		"",
   364  		[]string{common.DefaultFloatFieldName},
   365  		common.GenSearchVectors(common.DefaultNq, common.DefaultDim, entity.FieldTypeFloatVector),
   366  		common.DefaultFloatVecFieldName,
   367  		entity.L2,
   368  		common.DefaultTopK,
   369  		sp,
   370  	)
   371  	// check search result contains search vector, which from all partitions
   372  	common.CheckErr(t, err, true)
   373  	common.CheckSearchResult(t, searchRes, common.DefaultNq, common.DefaultTopK)
   374  
   375  }
   376  
   377  // test transfer replica of not existed collection
   378  func TestTransferReplicaNotExistedCollection(t *testing.T) {
   379  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   380  	// connect
   381  	mc := createMilvusClient(ctx, t)
   382  	resetRgs(t, ctx, mc)
   383  
   384  	// create new rg
   385  	rgName := common.GenRandomString(6)
   386  	errCreate := mc.CreateResourceGroup(ctx, rgName)
   387  	common.CheckErr(t, errCreate, true)
   388  
   389  	// transfer replica
   390  	errTransfer := mc.TransferReplica(ctx, common.DefaultRgName, rgName, common.GenRandomString(3), 1)
   391  	common.CheckErr(t, errTransfer, false, "collection not found")
   392  }
   393  
   394  // test transfer replicas with invalid replica number
   395  func TestTransferReplicaInvalidReplicaNumber(t *testing.T) {
   396  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   397  	// connect
   398  	mc := createMilvusClient(ctx, t)
   399  	resetRgs(t, ctx, mc)
   400  
   401  	// create new rg
   402  	rgName := common.GenRandomString(6)
   403  	errCreate := mc.CreateResourceGroup(ctx, rgName)
   404  	common.CheckErr(t, errCreate, true)
   405  
   406  	// create collection
   407  	collName := createDefaultCollection(ctx, t, mc, false, common.DefaultShards)
   408  
   409  	// invalid replicas
   410  	type invalidReplicasStruct struct {
   411  		replicaNumber int64
   412  		errMsg        string
   413  	}
   414  	invalidReplicas := []invalidReplicasStruct{
   415  		{replicaNumber: 0, errMsg: "invalid parameter[expected=NumReplica > 0][actual=invalid NumReplica 0]"},
   416  		{replicaNumber: -1, errMsg: "invalid parameter[expected=NumReplica > 0][actual=invalid NumReplica -1]"},
   417  		{replicaNumber: 1, errMsg: "Collection not loaded"},
   418  	}
   419  
   420  	for _, invalidReplica := range invalidReplicas {
   421  		// transfer replica
   422  		errTransfer := mc.TransferReplica(ctx, common.DefaultRgName, rgName, collName, invalidReplica.replicaNumber)
   423  		common.CheckErr(t, errTransfer, false, invalidReplica.errMsg)
   424  	}
   425  }
   426  
   427  // test transfer replicas rg not exist
   428  func TestTransferReplicaRgNotExisted(t *testing.T) {
   429  	ctx := createContext(t, time.Second*common.DefaultTimeout)
   430  	// connect
   431  	mc := createMilvusClient(ctx, t)
   432  	resetRgs(t, ctx, mc)
   433  
   434  	// create new rg and transfer nodes
   435  	rgName := common.GenRandomString(6)
   436  	errCreate := mc.CreateResourceGroup(ctx, rgName)
   437  	common.CheckErr(t, errCreate, true)
   438  	mc.TransferNode(ctx, common.DefaultRgName, rgName, newRgNode)
   439  
   440  	// init collection: create -> insert -> index -> load
   441  	collName, _ := createCollectionWithDataIndex(ctx, t, mc, true, true)
   442  	mc.LoadCollection(ctx, collName, false, client.WithResourceGroups([]string{rgName}))
   443  
   444  	// source not exist
   445  	errSource := mc.TransferReplica(ctx, common.GenRandomString(6), common.DefaultRgName, collName, 1)
   446  	common.CheckErr(t, errSource, false, "resource group not found")
   447  
   448  	// target not exist
   449  	errTarget := mc.TransferReplica(ctx, common.DefaultRgName, common.GenRandomString(6), collName, 1)
   450  	common.CheckErr(t, errTarget, false, "resource group not found")
   451  
   452  	// transfer to self -> error
   453  	errSelf := mc.TransferReplica(ctx, rgName, rgName, collName, 1)
   454  	common.CheckErr(t, errSelf, false, "source resource group and target resource group should not be the same")
   455  
   456  	// transfer to default rg
   457  	errTransfer := mc.TransferReplica(ctx, rgName, common.DefaultRgName, collName, 1)
   458  	common.CheckErr(t, errTransfer, true)
   459  	newRg, _ := mc.DescribeResourceGroup(ctx, rgName)
   460  	log.Print(newRg)
   461  	expRg := &entity.ResourceGroup{
   462  		Name:                 rgName,
   463  		Capacity:             newRgNode,
   464  		AvailableNodesNumber: newRgNode,
   465  		IncomingNodeNum:      map[string]int32{collName: newRgNode},
   466  	}
   467  	common.CheckResourceGroup(t, newRg, expRg)
   468  }