diff --git a/client/milvusclient/database.go b/client/milvusclient/database.go index 681dca15a1..f410f2b706 100644 --- a/client/milvusclient/database.go +++ b/client/milvusclient/database.go @@ -87,7 +87,7 @@ func (c *Client) DescribeDatabase(ctx context.Context, option DescribeDatabaseOp return db, err } -func (c *Client) AlterDatabaseProperies(ctx context.Context, option AlterDatabasePropertiesOption, callOptions ...grpc.CallOption) error { +func (c *Client) AlterDatabaseProperties(ctx context.Context, option AlterDatabasePropertiesOption, callOptions ...grpc.CallOption) error { req := option.Request() return c.callService(func(milvusService milvuspb.MilvusServiceClient) error { diff --git a/client/milvusclient/database_test.go b/client/milvusclient/database_test.go index 541f095d22..123e8215a4 100644 --- a/client/milvusclient/database_test.go +++ b/client/milvusclient/database_test.go @@ -153,7 +153,7 @@ func (s *DatabaseSuite) TestAlterDatabaseProperties() { return merr.Success(), nil }).Once() - err := s.client.AlterDatabaseProperies(ctx, NewAlterDatabasePropertiesOption(dbName).WithProperty(key, value)) + err := s.client.AlterDatabaseProperties(ctx, NewAlterDatabasePropertiesOption(dbName).WithProperty(key, value)) s.NoError(err) }) @@ -161,7 +161,7 @@ func (s *DatabaseSuite) TestAlterDatabaseProperties() { dbName := fmt.Sprintf("dt_%s", s.randString(6)) s.mock.EXPECT().AlterDatabase(mock.Anything, mock.Anything).Return(nil, merr.WrapErrServiceInternal("mocked")).Once() - err := s.client.AlterDatabaseProperies(ctx, NewAlterDatabasePropertiesOption(dbName).WithProperty("key", "value")) + err := s.client.AlterDatabaseProperties(ctx, NewAlterDatabasePropertiesOption(dbName).WithProperty("key", "value")) s.Error(err) }) } diff --git a/tests/go_client/base/milvus_client.go b/tests/go_client/base/milvus_client.go index 8a8f2a1175..d75035cd8d 100644 --- a/tests/go_client/base/milvus_client.go +++ b/tests/go_client/base/milvus_client.go @@ -88,14 +88,14 @@ func (mc *MilvusClient) Close(ctx context.Context) error { // -- database -- -// UsingDatabase list all database in milvus cluster. -func (mc *MilvusClient) UsingDatabase(ctx context.Context, option client.UseDatabaseOption) error { +// UseDatabase list all database in milvus cluster. +func (mc *MilvusClient) UseDatabase(ctx context.Context, option client.UseDatabaseOption) error { err := mc.mClient.UseDatabase(ctx, option) return err } -// ListDatabases list all database in milvus cluster. -func (mc *MilvusClient) ListDatabases(ctx context.Context, option client.ListDatabaseOption, callOptions ...grpc.CallOption) ([]string, error) { +// ListDatabase list all database in milvus cluster. +func (mc *MilvusClient) ListDatabase(ctx context.Context, option client.ListDatabaseOption, callOptions ...grpc.CallOption) ([]string, error) { databaseNames, err := mc.mClient.ListDatabase(ctx, option, callOptions...) return databaseNames, err } @@ -112,6 +112,24 @@ func (mc *MilvusClient) DropDatabase(ctx context.Context, option client.DropData return err } +// DescribeDatabase describe database with the given db name. +func (mc *MilvusClient) DescribeDatabase(ctx context.Context, option client.DescribeDatabaseOption, callOptions ...grpc.CallOption) (*entity.Database, error) { + database, err := mc.mClient.DescribeDatabase(ctx, option, callOptions...) + return database, err +} + +// AlterDatabaseProperties alter database properties +func (mc *MilvusClient) AlterDatabaseProperties(ctx context.Context, option client.AlterDatabasePropertiesOption, callOptions ...grpc.CallOption) error { + err := mc.mClient.AlterDatabaseProperties(ctx, option, callOptions...) + return err +} + +// DropDatabaseProperties drop database properties +func (mc *MilvusClient) DropDatabaseProperties(ctx context.Context, option client.DropDatabasePropertiesOption, callOptions ...grpc.CallOption) error { + err := mc.mClient.AlterDatabaseProperties(ctx, option, callOptions...) + return err +} + // -- collection -- // CreateCollection Create Collection diff --git a/tests/go_client/common/consts.go b/tests/go_client/common/consts.go index 91a6df94fb..fe97df0e68 100644 --- a/tests/go_client/common/consts.go +++ b/tests/go_client/common/consts.go @@ -76,3 +76,13 @@ const ( IndexStateFailed index.IndexState = 4 IndexStateRetry index.IndexState = 5 ) + +// part database properties +const ( + DatabaseMaxCollections = "database.max.collections" + DatabaseResourceGroups = "database.resource_groups" + DatabaseReplicaNumber = "database.replica.number" + DatabaseForceDenyWriting = "database.force.deny.writing" + DatabaseForceDenyReading = "database.force.deny.reading" + DatabaseDiskQuotaMb = "database.diskQuota.mb" +) diff --git a/tests/go_client/testcases/database_test.go b/tests/go_client/testcases/database_test.go index 745897e7fe..d87f976833 100644 --- a/tests/go_client/testcases/database_test.go +++ b/tests/go_client/testcases/database_test.go @@ -2,6 +2,7 @@ package testcases import ( "fmt" + "strconv" "testing" "time" @@ -23,10 +24,10 @@ func teardownTest(t *testing.T) func(t *testing.T) { // drop all db ctx := hp.CreateContext(t, time.Second*common.DefaultTimeout) mc := createDefaultMilvusClient(ctx, t) - dbs, _ := mc.ListDatabases(ctx, client.NewListDatabaseOption()) + dbs, _ := mc.ListDatabase(ctx, client.NewListDatabaseOption()) for _, db := range dbs { if db != common.DefaultDb { - _ = mc.UsingDatabase(ctx, client.NewUseDatabaseOption(db)) + _ = mc.UseDatabase(ctx, client.NewUseDatabaseOption(db)) collections, _ := mc.ListCollections(ctx, client.NewListCollectionOption()) for _, coll := range collections { _ = mc.DropCollection(ctx, client.NewDropCollectionOption(coll)) @@ -50,14 +51,14 @@ func TestDatabase(t *testing.T) { common.CheckErr(t, err, true) // list db and verify db1 in dbs - dbs, errList := clientDefault.ListDatabases(ctx, client.NewListDatabaseOption()) + dbs, errList := clientDefault.ListDatabase(ctx, client.NewListDatabaseOption()) common.CheckErr(t, errList, true) require.Containsf(t, dbs, dbName1, fmt.Sprintf("%s db not in dbs: %v", dbName1, dbs)) // new client with db1 -> using db clientDB1 := createMilvusClient(ctx, t, &client.ClientConfig{Address: *addr, DBName: dbName1}) t.Log("https://github.com/milvus-io/milvus/issues/34137") - err = clientDB1.UsingDatabase(ctx, client.NewUseDatabaseOption(dbName1)) + err = clientDB1.UseDatabase(ctx, client.NewUseDatabaseOption(dbName1)) common.CheckErr(t, err, true) // create collections -> verify collections contains @@ -72,24 +73,24 @@ func TestDatabase(t *testing.T) { dbName2 := common.GenRandomString("db2", 4) err = clientDefault.CreateDatabase(ctx, client.NewCreateDatabaseOption(dbName2)) common.CheckErr(t, err, true) - dbs, err = clientDefault.ListDatabases(ctx, client.NewListDatabaseOption()) + dbs, err = clientDefault.ListDatabase(ctx, client.NewListDatabaseOption()) common.CheckErr(t, err, true) require.Containsf(t, dbs, dbName2, fmt.Sprintf("%s db not in dbs: %v", dbName2, dbs)) // using db2 -> create collection -> drop collection - err = clientDefault.UsingDatabase(ctx, client.NewUseDatabaseOption(dbName2)) + err = clientDefault.UseDatabase(ctx, client.NewUseDatabaseOption(dbName2)) common.CheckErr(t, err, true) _, db2Col1 := hp.CollPrepare.CreateCollection(ctx, t, clientDefault, hp.NewCreateCollectionParams(hp.Int64Vec), hp.TNewFieldsOption(), hp.TNewSchemaOption()) err = clientDefault.DropCollection(ctx, client.NewDropCollectionOption(db2Col1.CollectionName)) common.CheckErr(t, err, true) // using empty db -> drop db2 - clientDefault.UsingDatabase(ctx, client.NewUseDatabaseOption("")) + clientDefault.UseDatabase(ctx, client.NewUseDatabaseOption("")) err = clientDefault.DropDatabase(ctx, client.NewDropDatabaseOption(dbName2)) common.CheckErr(t, err, true) // list db and verify db drop success - dbs, err = clientDefault.ListDatabases(ctx, client.NewListDatabaseOption()) + dbs, err = clientDefault.ListDatabase(ctx, client.NewListDatabaseOption()) common.CheckErr(t, err, true) require.NotContains(t, dbs, dbName2) @@ -98,7 +99,7 @@ func TestDatabase(t *testing.T) { common.CheckErr(t, err, false, "must drop all collections before drop database") // drop all db1's collections -> drop db1 - clientDB1.UsingDatabase(ctx, client.NewUseDatabaseOption(dbName1)) + clientDB1.UseDatabase(ctx, client.NewUseDatabaseOption(dbName1)) err = clientDB1.DropCollection(ctx, client.NewDropCollectionOption(db1Col1.CollectionName)) common.CheckErr(t, err, true) @@ -112,7 +113,7 @@ func TestDatabase(t *testing.T) { err = clientDefault.DropDatabase(ctx, client.NewDropDatabaseOption(common.DefaultDb)) common.CheckErr(t, err, false, "can not drop default database") - dbs, err = clientDefault.ListDatabases(ctx, client.NewListDatabaseOption()) + dbs, err = clientDefault.ListDatabase(ctx, client.NewListDatabaseOption()) common.CheckErr(t, err, true) require.Containsf(t, dbs, common.DefaultDb, fmt.Sprintf("The db %s not in: %v", common.DefaultDb, dbs)) } @@ -160,7 +161,7 @@ func TestDropDb(t *testing.T) { common.CheckErr(t, err, true) // using db and drop the db - err = mc.UsingDatabase(ctx, client.NewUseDatabaseOption(dbName)) + err = mc.UseDatabase(ctx, client.NewUseDatabaseOption(dbName)) common.CheckErr(t, err, true) err = mc.DropDatabase(ctx, client.NewDropDatabaseOption(dbName)) common.CheckErr(t, err, true) @@ -170,7 +171,7 @@ func TestDropDb(t *testing.T) { common.CheckErr(t, err, false, fmt.Sprintf("database not found[database=%s]", dbName)) // using default db and verify collections - err = mc.UsingDatabase(ctx, client.NewUseDatabaseOption(common.DefaultDb)) + err = mc.UseDatabase(ctx, client.NewUseDatabaseOption(common.DefaultDb)) common.CheckErr(t, err, true) collections, _ = mc.ListCollections(ctx, listCollOpt) require.Contains(t, collections, defCol.CollectionName) @@ -205,17 +206,17 @@ func TestUsingDb(t *testing.T) { // using not existed db dbName := common.GenRandomString("db", 4) - err := mc.UsingDatabase(ctx, client.NewUseDatabaseOption(dbName)) + err := mc.UseDatabase(ctx, client.NewUseDatabaseOption(dbName)) common.CheckErr(t, err, false, fmt.Sprintf("database not found[database=%s]", dbName)) // using empty db - err = mc.UsingDatabase(ctx, client.NewUseDatabaseOption("")) + err = mc.UseDatabase(ctx, client.NewUseDatabaseOption("")) common.CheckErr(t, err, true) collections, _ = mc.ListCollections(ctx, listCollOpt) require.Contains(t, collections, col.CollectionName) // using current db - err = mc.UsingDatabase(ctx, client.NewUseDatabaseOption(common.DefaultDb)) + err = mc.UseDatabase(ctx, client.NewUseDatabaseOption(common.DefaultDb)) common.CheckErr(t, err, true) collections, _ = mc.ListCollections(ctx, listCollOpt) require.Contains(t, collections, col.CollectionName) @@ -262,7 +263,7 @@ func TestClientWithDb(t *testing.T) { require.Containsf(t, dbCollections, dbCol1.CollectionName, fmt.Sprintf("The collection %s not in: %v", dbCol1.CollectionName, dbCollections)) // using default db and collection not in - _ = mcDb.UsingDatabase(ctx, client.NewUseDatabaseOption(common.DefaultDb)) + _ = mcDb.UseDatabase(ctx, client.NewUseDatabaseOption(common.DefaultDb)) defCollections, _ = mcDb.ListCollections(ctx, listCollOpt) require.NotContains(t, defCollections, dbCol1.CollectionName) @@ -276,6 +277,166 @@ func TestClientWithDb(t *testing.T) { require.Contains(t, defCollections, defCol1.CollectionName) } -func TestAlterDatabase(t *testing.T) { - t.Skip("waiting for AlterDatabase and DescribeDatabase") +func TestDatabasePropertiesCollectionsNum(t *testing.T) { + // create db with properties + teardownSuite := teardownTest(t) + defer teardownSuite(t) + + // create db + ctx := hp.CreateContext(t, time.Second*common.DefaultTimeout) + mc := createDefaultMilvusClient(ctx, t) + dbName := common.GenRandomString("db", 4) + err := mc.CreateDatabase(ctx, client.NewCreateDatabaseOption(dbName)) + common.CheckErr(t, err, true) + + // alter database properties + maxCollections := 2 + err = mc.AlterDatabaseProperties(ctx, client.NewAlterDatabasePropertiesOption(dbName).WithProperty(common.DatabaseMaxCollections, maxCollections)) + common.CheckErr(t, err, true) + + // describe database + db, _ := mc.DescribeDatabase(ctx, client.NewDescribeDatabaseOption(dbName)) + require.Equal(t, map[string]string{common.DatabaseMaxCollections: strconv.Itoa(maxCollections)}, db.Properties) + require.Equal(t, dbName, db.Name) + + // verify properties works + mc.UseDatabase(ctx, client.NewUseDatabaseOption(dbName)) + var collections []string + for i := 0; i < maxCollections; i++ { + _, schema := hp.CollPrepare.CreateCollection(ctx, t, mc, hp.NewCreateCollectionParams(hp.Int64Vec), hp.TNewFieldsOption(), hp.TNewSchemaOption()) + collections = append(collections, schema.CollectionName) + } + fields := hp.FieldsFact.GenFieldsForCollection(hp.Int64Vec, hp.TNewFieldsOption()) + schema := hp.GenSchema(hp.TNewSchemaOption().TWithFields(fields)) + err = mc.CreateCollection(ctx, client.NewCreateCollectionOption(schema.CollectionName, schema)) + common.CheckErr(t, err, false, "exceeded the limit number of collections") + + // Other db are not restricted by this property + mc.UseDatabase(ctx, client.NewUseDatabaseOption(common.DefaultDb)) + for i := 0; i < maxCollections+1; i++ { + hp.CollPrepare.CreateCollection(ctx, t, mc, hp.NewCreateCollectionParams(hp.Int64Vec), hp.TNewFieldsOption(), hp.TNewSchemaOption()) + } + + // drop properties + mc.UseDatabase(ctx, client.NewUseDatabaseOption(dbName)) + errDrop := mc.DropDatabaseProperties(ctx, client.NewDropDatabasePropertiesOption(dbName, common.DatabaseMaxCollections)) + common.CheckErr(t, errDrop, true) + _, schema1 := hp.CollPrepare.CreateCollection(ctx, t, mc, hp.NewCreateCollectionParams(hp.Int64Vec), hp.TNewFieldsOption(), hp.TNewSchemaOption()) + collections = append(collections, schema1.CollectionName) + + // verify collection num + collectionsList, _ := mc.ListCollections(ctx, client.NewListCollectionOption()) + require.Subset(t, collectionsList, collections) + require.GreaterOrEqual(t, len(collectionsList), maxCollections) + + // describe database after drop properties + db, _ = mc.DescribeDatabase(ctx, client.NewDescribeDatabaseOption(dbName)) + require.Equal(t, map[string]string{}, db.Properties) + require.Equal(t, dbName, db.Name) +} + +func TestDatabasePropertiesRgReplicas(t *testing.T) { + // create db with properties + teardownSuite := teardownTest(t) + defer teardownSuite(t) + + // create db + ctx := hp.CreateContext(t, time.Second*common.DefaultTimeout) + mc := createDefaultMilvusClient(ctx, t) + dbName := common.GenRandomString("db", 4) + err := mc.CreateDatabase(ctx, client.NewCreateDatabaseOption(dbName)) + common.CheckErr(t, err, true) + + // alter database properties + err = mc.AlterDatabaseProperties(ctx, client.NewAlterDatabasePropertiesOption(dbName). + WithProperty(common.DatabaseResourceGroups, "rg1").WithProperty(common.DatabaseReplicaNumber, 2)) + common.CheckErr(t, err, true) + + // describe database + db, _ := mc.DescribeDatabase(ctx, client.NewDescribeDatabaseOption(dbName)) + require.Equal(t, map[string]string{common.DatabaseResourceGroups: "rg1", common.DatabaseReplicaNumber: "2"}, db.Properties) + + mc.UseDatabase(ctx, client.NewUseDatabaseOption(dbName)) + prepare, schema := hp.CollPrepare.CreateCollection(ctx, t, mc, hp.NewCreateCollectionParams(hp.Int64Vec), hp.TNewFieldsOption(), hp.TNewSchemaOption().TWithEnableDynamicField(true)) + prepare.InsertData(ctx, t, mc, hp.NewInsertParams(schema), hp.TNewDataOption().TWithNb(1000)) + prepare.FlushData(ctx, t, mc, schema.CollectionName) + prepare.CreateIndex(ctx, t, mc, hp.TNewIndexParams(schema)) + + _, err = mc.LoadCollection(ctx, client.NewLoadCollectionOption(schema.CollectionName)) + common.CheckErr(t, err, true) + + _, err = mc.Query(ctx, client.NewQueryOption(schema.CollectionName).WithLimit(10)) + common.CheckErr(t, err, true) +} + +func TestDatabasePropertyDeny(t *testing.T) { + t.Skip("https://zilliz.atlassian.net/browse/VDC-7858") + // create db with properties + teardownSuite := teardownTest(t) + defer teardownSuite(t) + + // create db and use db + ctx := hp.CreateContext(t, time.Second*common.DefaultTimeout) + mc := createDefaultMilvusClient(ctx, t) + dbName := common.GenRandomString("db", 4) + err := mc.CreateDatabase(ctx, client.NewCreateDatabaseOption(dbName)) + common.CheckErr(t, err, true) + + // alter database properties and check + err = mc.AlterDatabaseProperties(ctx, client.NewAlterDatabasePropertiesOption(dbName). + WithProperty(common.DatabaseForceDenyWriting, true). + WithProperty(common.DatabaseForceDenyReading, true)) + common.CheckErr(t, err, true) + db, _ := mc.DescribeDatabase(ctx, client.NewDescribeDatabaseOption(dbName)) + require.Equal(t, map[string]string{common.DatabaseForceDenyWriting: "true", common.DatabaseForceDenyReading: "true"}, db.Properties) + + err = mc.UseDatabase(ctx, client.NewUseDatabaseOption(dbName)) + common.CheckErr(t, err, true) + + // prepare collection: create -> index -> load + prepare, schema := hp.CollPrepare.CreateCollection(ctx, t, mc, hp.NewCreateCollectionParams(hp.Int64Vec), hp.TNewFieldsOption(), hp.TNewSchemaOption().TWithEnableDynamicField(true)) + prepare.CreateIndex(ctx, t, mc, hp.TNewIndexParams(schema)) + prepare.Load(ctx, t, mc, hp.NewLoadParams(schema.CollectionName)) + + // reading + _, err = mc.Query(ctx, client.NewQueryOption(schema.CollectionName).WithLimit(10)) + common.CheckErr(t, err, false, "access has been disabled by the administrator") + + // writing + columns, _ := hp.GenColumnsBasedSchema(schema, hp.TNewDataOption().TWithNb(10)) + _, err = mc.Insert(ctx, client.NewColumnBasedInsertOption(schema.CollectionName, columns...)) + common.CheckErr(t, err, false, "access has been disabled by the administrator") +} + +func TestDatabaseFakeProperties(t *testing.T) { + // create db with properties + teardownSuite := teardownTest(t) + defer teardownSuite(t) + + // create db + ctx := hp.CreateContext(t, time.Second*common.DefaultTimeout) + mc := createDefaultMilvusClient(ctx, t) + dbName := common.GenRandomString("db", 4) + err := mc.CreateDatabase(ctx, client.NewCreateDatabaseOption(dbName)) + common.CheckErr(t, err, true) + + // alter database with useless properties + properties := map[string]any{ + "key_1": 1, + "key2": 1.9, + "key-3": true, + "key.4": "a.b.c", + } + for key, value := range properties { + err = mc.AlterDatabaseProperties(ctx, client.NewAlterDatabasePropertiesOption(dbName).WithProperty(key, value)) + common.CheckErr(t, err, true) + } + + // describe database + db, _ := mc.DescribeDatabase(ctx, client.NewDescribeDatabaseOption(dbName)) + require.EqualValues(t, map[string]string{"key_1": "1", "key2": "1.9", "key-3": "true", "key.4": "a.b.c"}, db.Properties) + + // drop database properties + err = mc.DropDatabaseProperties(ctx, client.NewDropDatabasePropertiesOption(dbName, "aaa")) + common.CheckErr(t, err, true) } diff --git a/tests/go_client/testcases/helper/helper.go b/tests/go_client/testcases/helper/helper.go index c2d6fe7b94..2c7e74c326 100644 --- a/tests/go_client/testcases/helper/helper.go +++ b/tests/go_client/testcases/helper/helper.go @@ -104,7 +104,7 @@ func GetInvalidPartitionKeyFieldType() []entity.FieldType { return nonPkFieldTypes } -// ----------------- prepare data -------------------------- +// CollectionPrepare ----------------- prepare data -------------------------- type CollectionPrepare struct{} var ( diff --git a/tests/go_client/testcases/main_test.go b/tests/go_client/testcases/main_test.go index 918d3e7da7..e541445acf 100644 --- a/tests/go_client/testcases/main_test.go +++ b/tests/go_client/testcases/main_test.go @@ -33,10 +33,10 @@ func teardown() { defer mc.Close(ctx) // clear dbs - dbs, _ := mc.ListDatabases(ctx, clientv2.NewListDatabaseOption()) + dbs, _ := mc.ListDatabase(ctx, clientv2.NewListDatabaseOption()) for _, db := range dbs { if db != common.DefaultDb { - _ = mc.UsingDatabase(ctx, clientv2.NewUseDatabaseOption(db)) + _ = mc.UseDatabase(ctx, clientv2.NewUseDatabaseOption(db)) collections, _ := mc.ListCollections(ctx, clientv2.NewListCollectionOption()) for _, coll := range collections { _ = mc.DropCollection(ctx, clientv2.NewDropCollectionOption(coll))