From c32df86c761abe08904c7c21ef694778f5a6e2ea Mon Sep 17 00:00:00 2001 From: Daniel Valdivia Date: Wed, 29 Apr 2020 10:54:59 -0700 Subject: [PATCH] use target implementation on config api (#81) Co-authored-by: Cesar Nieto --- go.mod | 4 +- go.sum | 12 + restapi/admin_config.go | 35 +- restapi/admin_config_test.go | 808 +++++++++++++++++++++++------------ 4 files changed, 559 insertions(+), 300 deletions(-) diff --git a/go.mod b/go.mod index 430c2367a..6ae57105f 100644 --- a/go.mod +++ b/go.mod @@ -16,8 +16,8 @@ require ( github.com/json-iterator/go v1.1.9 github.com/minio/cli v1.22.0 github.com/minio/mc v0.0.0-20200415193718-68b638f2f96c - github.com/minio/minio v0.0.0-20200415191640-bde0f444dbab - github.com/minio/minio-go/v6 v6.0.53 + github.com/minio/minio v0.0.0-20200427162205-eff4127efd63 + github.com/minio/minio-go/v6 v6.0.55-0.20200424204115-7506d2996b22 github.com/satori/go.uuid v1.2.0 github.com/stretchr/testify v1.5.1 github.com/unrolled/secure v1.0.7 diff --git a/go.sum b/go.sum index 3f7483274..4055a8f09 100644 --- a/go.sum +++ b/go.sum @@ -388,8 +388,20 @@ github.com/minio/mc v0.0.0-20200415193718-68b638f2f96c h1:JLr0fYpCleodj9nGB5hfsJ github.com/minio/mc v0.0.0-20200415193718-68b638f2f96c/go.mod h1:l9PuOY62zT7AQJqopDjfo/T22AIBJSb2yXPVZf4RlhM= github.com/minio/minio v0.0.0-20200415191640-bde0f444dbab h1:9hlqghJl3e3HorXa6ADWsz6ECq790t4iQs07VD9JctM= github.com/minio/minio v0.0.0-20200415191640-bde0f444dbab/go.mod h1:v8oQPMMaTkjDwp5cOz1WCElA4Ik+X+0y4On+VMk0fis= +github.com/minio/minio v0.0.0-20200421050159-282c9f790a03 h1:qEWJAXNbLp1Uovs9gzPQ8gWGFY8X+58WcttySAMgny0= +github.com/minio/minio v0.0.0-20200421050159-282c9f790a03/go.mod h1:zBua5AiljGs1Irdl2XEyiJjvZVCVDIG8gjozzRBcVlw= +github.com/minio/minio v0.0.0-20200422230658-6817c5ea58fb h1:qDqH+rGTsORP1Y7M8JSswlWPl5L35C9fuz9VR2qhe8Y= +github.com/minio/minio v0.0.0-20200422230658-6817c5ea58fb/go.mod h1:zBua5AiljGs1Irdl2XEyiJjvZVCVDIG8gjozzRBcVlw= +github.com/minio/minio v0.0.0-20200424205148-45e22cf8aa2a h1:KKMhJEuVCtfrDDtrG5BT5pp37ZjqGSUEX/yOlJLrhD4= +github.com/minio/minio v0.0.0-20200424205148-45e22cf8aa2a/go.mod h1:zBua5AiljGs1Irdl2XEyiJjvZVCVDIG8gjozzRBcVlw= +github.com/minio/minio v0.0.0-20200427162205-eff4127efd63 h1:hLWy7ugfhRfyPoIiflLe7lKnKy8O61LUX1G8rSJXZLQ= +github.com/minio/minio v0.0.0-20200427162205-eff4127efd63/go.mod h1:7Zkko5V0gucT+jh6wDhao6n78MZ6exxHSawsH897VaA= github.com/minio/minio-go/v6 v6.0.53 h1:8jzpwiOzZ5Iz7/goFWqNZRICbyWYShbb5rARjrnSCNI= github.com/minio/minio-go/v6 v6.0.53/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI= +github.com/minio/minio-go/v6 v6.0.54 h1:3bUIEVa5hkVqY7vTGY8yfO53qP5CiSddM8OOPSU0JxQ= +github.com/minio/minio-go/v6 v6.0.54/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI= +github.com/minio/minio-go/v6 v6.0.55-0.20200424204115-7506d2996b22 h1:nZEve4vdUhwHBoV18zRvPDgjL6NYyDJE5QJvz3l9bRs= +github.com/minio/minio-go/v6 v6.0.55-0.20200424204115-7506d2996b22/go.mod h1:KQMM+/44DSlSGSQWSfRrAZ12FVMmpWNuX37i2AX0jfI= github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61 h1:pUSI/WKPdd77gcuoJkSzhJ4wdS8OMDOsOu99MtpXEQA= github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61/go.mod h1:4trzEJ7N1nBTd5Tt7OCZT5SEin+WiAXpdJ/WgPkESA8= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= diff --git a/restapi/admin_config.go b/restapi/admin_config.go index d3cf82cad..5be8003c9 100644 --- a/restapi/admin_config.go +++ b/restapi/admin_config.go @@ -26,6 +26,7 @@ import ( "github.com/go-openapi/swag" "github.com/minio/mcs/models" "github.com/minio/mcs/restapi/operations" + madmin "github.com/minio/minio/pkg/madmin" "github.com/minio/mcs/restapi/operations/admin_api" ) @@ -103,25 +104,29 @@ func getListConfigResponse(sessionID string) (*models.ListConfigResponse, error) // getConfig gets the key values for a defined configuration func getConfig(client MinioAdmin, name string) ([]*models.ConfigurationKV, error) { ctx := context.Background() - // getConfigKV comes as []byte - configBytes, err := client.getConfigKV(ctx, name) + + configKeysHelp, err := client.helpConfigKV(ctx, name, "", false) + if err != nil { + return nil, err + } + configBytes, err := client.getConfigKV(ctx, name) if err != nil { - log.Println("error on getConfigKV") return nil, err } - // if len(config) > 0 { - // // return Key Values, first element contains info - // var confkv []*models.ConfigurationKV - // for _, kv := range config[0].KVS { - // confkv = append(confkv, &models.ConfigurationKV{Key: kv.Key, Value: kv.Value}) - // } - // return confkv, nil - // } - // TODO: Provisional until function to get key values is done - var confkv []*models.ConfigurationKV - confkv = append(confkv, &models.ConfigurationKV{Key: "configuration", Value: string(configBytes)}) - return confkv, nil + target, err := madmin.ParseSubSysTarget(configBytes, configKeysHelp) + if err != nil { + return nil, err + } + if len(target.KVS) > 0 { + // return Key Values, first element contains info + var confkv []*models.ConfigurationKV + for _, kv := range target.KVS { + confkv = append(confkv, &models.ConfigurationKV{Key: kv.Key, Value: kv.Value}) + } + return confkv, nil + } + return nil, fmt.Errorf("error retrieving configuration for: %s", name) } // getConfigResponse performs getConfig() and serializes it to the handler's output diff --git a/restapi/admin_config_test.go b/restapi/admin_config_test.go index a793e5b32..cfe1e2e3e 100644 --- a/restapi/admin_config_test.go +++ b/restapi/admin_config_test.go @@ -17,7 +17,22 @@ package restapi import ( + "bytes" "context" + "encoding/json" + "errors" + "fmt" + "reflect" + "testing" + + "github.com/go-openapi/swag" + "github.com/stretchr/testify/assert" + + "github.com/minio/minio/pkg/event/target" + + "github.com/minio/minio/cmd/config" + + "github.com/minio/mcs/models" "github.com/minio/minio/pkg/madmin" ) @@ -42,297 +57,524 @@ func (ac adminClientMock) setConfigKV(ctx context.Context, kv string) error { return minioSetConfigKVMock(kv) } -// func TestListConfig(t *testing.T) { -// assert := assert.New(t) -// adminClient := adminClientMock{} -// function := "listConfig()" -// // Test-1 : listConfig() get list of two configurations and ensure is output correctly -// configListMock := []madmin.HelpKV{ -// madmin.HelpKV{ -// Key: "region", -// Description: "label the location of the server", -// }, -// madmin.HelpKV{ -// Key: "notify_nsq", -// Description: "publish bucket notifications to NSQ endpoints", -// }, -// } -// mockConfigList := madmin.Help{ -// SubSys: "sys", -// Description: "desc", -// MultipleTargets: false, -// KeysHelp: configListMock, -// } -// expectedKeysDesc := mockConfigList.KeysHelp -// // mock function response from listConfig() -// minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) { -// return mockConfigList, nil -// } -// configList, err := listConfig(adminClient) -// if err != nil { -// t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) -// } -// // verify length of keys is correct -// assert.Equal(len(expectedKeysDesc), len(configList), fmt.Sprintf("Failed on %s: length of Configs's lists is not the same", function)) -// // verify KeysHelp content -// for i, kv := range configList { -// assert.Equal(expectedKeysDesc[i].Key, kv.Key) -// assert.Equal(expectedKeysDesc[i].Description, kv.Description) -// } +func TestListConfig(t *testing.T) { + assert := assert.New(t) + adminClient := adminClientMock{} + function := "listConfig()" + // Test-1 : listConfig() get list of two configurations and ensure is output correctly + configListMock := []madmin.HelpKV{ + madmin.HelpKV{ + Key: "region", + Description: "label the location of the server", + }, + madmin.HelpKV{ + Key: "notify_nsq", + Description: "publish bucket notifications to NSQ endpoints", + }, + } + mockConfigList := madmin.Help{ + SubSys: "sys", + Description: "desc", + MultipleTargets: false, + KeysHelp: configListMock, + } + expectedKeysDesc := mockConfigList.KeysHelp + // mock function response from listConfig() + minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) { + return mockConfigList, nil + } + configList, err := listConfig(adminClient) + if err != nil { + t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) + } + // verify length of keys is correct + assert.Equal(len(expectedKeysDesc), len(configList), fmt.Sprintf("Failed on %s: length of Configs's lists is not the same", function)) + // verify KeysHelp content + for i, kv := range configList { + assert.Equal(expectedKeysDesc[i].Key, kv.Key) + assert.Equal(expectedKeysDesc[i].Description, kv.Description) + } -// // Test-2 : listConfig() Return error and see that the error is handled correctly and returned -// // mock function response from listConfig() -// minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) { -// return madmin.Help{}, errors.New("error") -// } -// _, err = listConfig(adminClient) -// if assert.Error(err) { -// assert.Equal("error", err.Error()) -// } -// } + // Test-2 : listConfig() Return error and see that the error is handled correctly and returned + // mock function response from listConfig() + minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) { + return madmin.Help{}, errors.New("error") + } + _, err = listConfig(adminClient) + if assert.Error(err) { + assert.Equal("error", err.Error()) + } +} -// func TestGetConfigInfo(t *testing.T) { -// assert := assert.New(t) -// adminClient := adminClientMock{} -// function := "getConfig()" -// // Test-1 : getConfig() get info of postgres configuration, has 3 key-value pairs -// configMock := []madmin.Target{ -// madmin.Target{ -// SubSystem: "notify_postgres", -// KVS: []madmin.KV{ -// madmin.KV{ -// Key: "enable", -// Value: "off", -// }, -// madmin.KV{ -// Key: "format", -// Value: "namespace", -// }, -// madmin.KV{ -// Key: "connection", -// Value: "", -// }, -// }, -// }, -// } -// expectedKV := configMock[0].KVS -// // mock function response from getConfig() -// minioGetConfigKVMock = func(key string) (madmin.Targets, error) { -// return configMock, nil -// } -// configNameToGet := "notify_postgres" -// configInfo, err := getConfig(adminClient, configNameToGet) -// if err != nil { -// t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) -// } -// // verify length of keys is correct -// assert.Equal(len(expectedKV), len(configInfo), fmt.Sprintf("Failed on %s: length of Configs's lists is not the same", function)) -// // verify KeysHelp content -// for i, kv := range configInfo { -// assert.Equal(expectedKV[i].Key, kv.Key) -// assert.Equal(expectedKV[i].Value, kv.Value) -// } +func TestSetConfig(t *testing.T) { + assert := assert.New(t) + adminClient := adminClientMock{} + function := "setConfig()" + // mock function response from setConfig() + minioSetConfigKVMock = func(kv string) error { + return nil + } + configName := "notify_postgres" + kvs := []*models.ConfigurationKV{ + { + Key: "enable", + Value: "off", + }, + { + Key: "connection_string", + Value: "", + }, + } -// // Test-2 : getConfig() Return error and see that the error is handled correctly and returned -// minioGetConfigKVMock = func(key string) (madmin.Targets, error) { -// return madmin.Targets{}, errors.New("error") -// } -// _, err = getConfig(adminClient, configNameToGet) -// if assert.Error(err) { -// assert.Equal("error", err.Error()) -// } + ctx := context.Background() + // Test-1 : setConfig() sets a config with two key value pairs + err := setConfig(ctx, adminClient, &configName, kvs) + if err != nil { + t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) + } -// // Test-3 : getConfig() get info but Response has empty results (possible) -// configMock = []madmin.Target{} -// // mock function response from getConfig() -// minioGetConfigKVMock = func(key string) (madmin.Targets, error) { -// return configMock, nil -// } -// configNameToGet = "notify_postgres" -// _, err = getConfig(adminClient, configNameToGet) -// if assert.Error(err) { -// assert.Equal("error getting config: empty info", err.Error()) -// } -// } + // Test-2 : setConfig() returns error, handle properly + minioSetConfigKVMock = func(kv string) error { + return errors.New("error") + } + if err := setConfig(ctx, adminClient, &configName, kvs); assert.Error(err) { + assert.Equal("error", err.Error()) + } -// func TestSetConfig(t *testing.T) { -// assert := assert.New(t) -// adminClient := adminClientMock{} -// function := "setConfig()" -// // mock function response from setConfig() -// minioSetConfigKVMock = func(kv string) error { -// return nil -// } -// configName := "notify_postgres" -// kvs := []*models.ConfigurationKV{ -// { -// Key: "enable", -// Value: "off", -// }, -// { -// Key: "connection_string", -// Value: "", -// }, -// } +} -// ctx := context.Background() -// // Test-1 : setConfig() sets a config with two key value pairs -// err := setConfig(ctx, adminClient, &configName, kvs) -// if err != nil { -// t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) -// } +func Test_buildConfig(t *testing.T) { + type args struct { + configName *string + kvs []*models.ConfigurationKV + } + tests := []struct { + name string + args args + want *string + }{ + // Test-1: buildConfig() format correctly configuration as "config_name k=v k2=v2" + { + name: "format correctly", + args: args{ + configName: swag.String("notify_postgres"), + kvs: []*models.ConfigurationKV{ + { + Key: "enable", + Value: "off", + }, + { + Key: "connection_string", + Value: "", + }, + }, + }, + want: swag.String("notify_postgres enable=off connection_string="), + }, + // Test-2: buildConfig() format correctly configuration as "config_name k=v k2=v2 k2=v3" with duplicate keys + { + name: "duplicated keys in config", + args: args{ + configName: swag.String("notify_postgres"), + kvs: []*models.ConfigurationKV{ + { + Key: "enable", + Value: "off", + }, + { + Key: "connection_string", + Value: "", + }, + { + Key: "connection_string", + Value: "x", + }, + }, + }, + want: swag.String("notify_postgres enable=off connection_string= connection_string=x"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := buildConfig(tt.args.configName, tt.args.kvs); !reflect.DeepEqual(got, tt.want) { + t.Errorf("buildConfig() = %s, want %s", *got, *tt.want) + } + }) + } +} -// // Test-2 : setConfig() returns error, handle properly -// minioSetConfigKVMock = func(kv string) error { -// return errors.New("error") -// } -// if err := setConfig(ctx, adminClient, &configName, kvs); assert.Error(err) { -// assert.Equal("error", err.Error()) -// } +func Test_setConfigWithARN(t *testing.T) { + client := adminClientMock{} -// } + type args struct { + ctx context.Context + client MinioAdmin + configName *string + kvs []*models.ConfigurationKV + arn string + } + tests := []struct { + name string + args args + mockSetConfig func(kv string) error + wantErr bool + }{ + { + name: "Set valid config with arn", + args: args{ + ctx: context.Background(), + client: client, + configName: swag.String("notify_kafka"), + kvs: []*models.ConfigurationKV{ + { + Key: "brokers", + Value: "http://localhost:8080/broker1,http://localhost:8080/broker2", + }, + }, + arn: "1", + }, + mockSetConfig: func(kv string) error { + return nil + }, + wantErr: false, + }, + { + name: "Set valid config without arn", + args: args{ + ctx: context.Background(), + client: client, + configName: swag.String("region"), + kvs: []*models.ConfigurationKV{ + { + Key: "name", + Value: "us-west-1", + }, + }, + arn: "", + }, + mockSetConfig: func(kv string) error { + return nil + }, + wantErr: false, + }, + { + name: "Setting an incorrect config", + args: args{ + ctx: context.Background(), + client: client, + configName: swag.String("oorgle"), + kvs: []*models.ConfigurationKV{ + { + Key: "name", + Value: "us-west-1", + }, + }, + arn: "", + }, + mockSetConfig: func(kv string) error { + return errors.New("error") + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // mock function response from setConfig() + minioSetConfigKVMock = tt.mockSetConfig + if err := setConfigWithARNAccountID(tt.args.ctx, tt.args.client, tt.args.configName, tt.args.kvs, tt.args.arn); (err != nil) != tt.wantErr { + t.Errorf("setConfigWithARNAccountID() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} -// func Test_buildConfig(t *testing.T) { -// type args struct { -// configName *string -// kvs []*models.ConfigurationKV -// } -// tests := []struct { -// name string -// args args -// want *string -// }{ -// // Test-1: buildConfig() format correctly configuration as "config_name k=v k2=v2" -// { -// name: "format correctly", -// args: args{ -// configName: swag.String("notify_postgres"), -// kvs: []*models.ConfigurationKV{ -// { -// Key: "enable", -// Value: "off", -// }, -// { -// Key: "connection_string", -// Value: "", -// }, -// }, -// }, -// want: swag.String("notify_postgres enable=off connection_string="), -// }, -// // Test-2: buildConfig() format correctly configuration as "config_name k=v k2=v2 k2=v3" with duplicate keys -// { -// name: "duplicated keys in config", -// args: args{ -// configName: swag.String("notify_postgres"), -// kvs: []*models.ConfigurationKV{ -// { -// Key: "enable", -// Value: "off", -// }, -// { -// Key: "connection_string", -// Value: "", -// }, -// { -// Key: "connection_string", -// Value: "x", -// }, -// }, -// }, -// want: swag.String("notify_postgres enable=off connection_string= connection_string=x"), -// }, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// if got := buildConfig(tt.args.configName, tt.args.kvs); !reflect.DeepEqual(got, tt.want) { -// t.Errorf("buildConfig() = %s, want %s", *got, *tt.want) -// } -// }) -// } -// } +func Test_getConfig(t *testing.T) { + client := adminClientMock{} + type args struct { + client MinioAdmin + name string + } + tests := []struct { + name string + args args + mock func() + want []*models.ConfigurationKV + wantErr bool + }{ + { + name: "get config", + args: args{ + client: client, + name: "notify_postgres", + }, + mock: func() { + cfg := config.Config{} + cfg["notify_postgres"] = make(map[string]config.KVS) + cfg["notify_postgres"]["_"] = config.KVS{ + { + Key: target.PostgresConnectionString, + Value: "host=localhost dbname=minio_events user=postgres password=password port=5432 sslmode=disable", + }, + { + Key: target.PostgresTable, + Value: "bucketevents", + }, + } -// func Test_setConfigWithARN(t *testing.T) { -// client := adminClientMock{} + var buf = &bytes.Buffer{} + cw := config.NewConfigWriteTo(cfg, "notify_postgres:_") + cw.WriteTo(buf) -// type args struct { -// ctx context.Context -// client MinioAdmin -// configName *string -// kvs []*models.ConfigurationKV -// arn string -// } -// tests := []struct { -// name string -// args args -// mockSetConfig func(kv string) error -// wantErr bool -// }{ -// { -// name: "Set valid config with arn", -// args: args{ -// ctx: context.Background(), -// client: client, -// configName: swag.String("notify_kafka"), -// kvs: []*models.ConfigurationKV{ -// { -// Key: "brokers", -// Value: "http://localhost:8080/broker1,http://localhost:8080/broker2", -// }, -// }, -// arn: "1", -// }, -// mockSetConfig: func(kv string) error { -// return nil -// }, -// wantErr: false, -// }, -// { -// name: "Set valid config without arn", -// args: args{ -// ctx: context.Background(), -// client: client, -// configName: swag.String("region"), -// kvs: []*models.ConfigurationKV{ -// { -// Key: "name", -// Value: "us-west-1", -// }, -// }, -// arn: "", -// }, -// mockSetConfig: func(kv string) error { -// return nil -// }, -// wantErr: false, -// }, -// { -// name: "Setting an incorrect config", -// args: args{ -// ctx: context.Background(), -// client: client, -// configName: swag.String("oorgle"), -// kvs: []*models.ConfigurationKV{ -// { -// Key: "name", -// Value: "us-west-1", -// }, -// }, -// arn: "", -// }, -// mockSetConfig: func(kv string) error { -// return errors.New("error") -// }, -// wantErr: true, -// }, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// // mock function response from setConfig() -// minioSetConfigKVMock = tt.mockSetConfig -// if err := setConfigWithARNAccountID(tt.args.ctx, tt.args.client, tt.args.configName, tt.args.kvs, tt.args.arn); (err != nil) != tt.wantErr { -// t.Errorf("setConfigWithARNAccountID() error = %v, wantErr %v", err, tt.wantErr) -// } -// }) -// } -// } + // mock function response from getConfig() + minioGetConfigKVMock = func(key string) ([]byte, error) { + return buf.Bytes(), nil + } + + configListMock := []madmin.HelpKV{ + { + Key: target.PostgresConnectionString, + Description: `Postgres server connection-string e.g. "host=localhost port=5432 dbname=minio_events user=postgres password=password sslmode=disable"`, + Type: "string", + }, + { + Key: target.PostgresTable, + Description: "DB table name to store/update events, table is auto-created", + Type: "string", + }, + { + Key: target.PostgresFormat, + Description: "desc", + Type: "namespace*|access", + }, + { + Key: target.PostgresQueueDir, + Description: "des", + Optional: true, + Type: "path", + }, + { + Key: target.PostgresQueueLimit, + Description: "desc", + Optional: true, + Type: "number", + }, + { + Key: config.Comment, + Description: config.DefaultComment, + Optional: true, + Type: "sentence", + }, + } + mockConfigList := madmin.Help{ + SubSys: config.NotifyPostgresSubSys, + Description: "publish bucket notifications to Postgres databases", + MultipleTargets: true, + KeysHelp: configListMock, + } + // mock function response from listConfig() + minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) { + return mockConfigList, nil + } + }, + want: []*models.ConfigurationKV{ + { + Key: target.PostgresConnectionString, + Value: "host=localhost dbname=minio_events user=postgres password=password port=5432 sslmode=disable", + }, + { + Key: target.PostgresTable, + Value: "bucketevents", + }, + }, + wantErr: false, + }, + { + name: "valid config, but server returned empty", + args: args{ + client: client, + name: "notify_postgres", + }, + mock: func() { + cfg := config.Config{} + cfg["notify_postgres"] = make(map[string]config.KVS) + cfg["notify_postgres"]["_"] = config.KVS{} + + var buf = &bytes.Buffer{} + cw := config.NewConfigWriteTo(cfg, "notify_postgres:_") + cw.WriteTo(buf) + + // mock function response from getConfig() + minioGetConfigKVMock = func(key string) ([]byte, error) { + return buf.Bytes(), nil + } + + configListMock := []madmin.HelpKV{ + { + Key: target.PostgresConnectionString, + Description: `Postgres server connection-string e.g. "host=localhost port=5432 dbname=minio_events user=postgres password=password sslmode=disable"`, + Type: "string", + }, + { + Key: target.PostgresTable, + Description: "DB table name to store/update events, table is auto-created", + Type: "string", + }, + { + Key: target.PostgresFormat, + Description: "desc", + Type: "namespace*|access", + }, + { + Key: target.PostgresQueueDir, + Description: "des", + Optional: true, + Type: "path", + }, + { + Key: target.PostgresQueueLimit, + Description: "desc", + Optional: true, + Type: "number", + }, + { + Key: config.Comment, + Description: config.DefaultComment, + Optional: true, + Type: "sentence", + }, + } + mockConfigList := madmin.Help{ + SubSys: config.NotifyPostgresSubSys, + Description: "publish bucket notifications to Postgres databases", + MultipleTargets: true, + KeysHelp: configListMock, + } + // mock function response from listConfig() + minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) { + return mockConfigList, nil + } + }, + want: nil, + wantErr: true, + }, + { + name: "random bytes coming out of getConfigKv", + args: args{ + client: client, + name: "notify_postgres", + }, + mock: func() { + + // mock function response from getConfig() + minioGetConfigKVMock = func(key string) ([]byte, error) { + x := make(map[string]string) + x["x"] = "x" + j, _ := json.Marshal(x) + return j, nil + } + + configListMock := []madmin.HelpKV{ + { + Key: target.PostgresConnectionString, + Description: `Postgres server connection-string e.g. "host=localhost port=5432 dbname=minio_events user=postgres password=password sslmode=disable"`, + Type: "string", + }, + { + Key: target.PostgresTable, + Description: "DB table name to store/update events, table is auto-created", + Type: "string", + }, + { + Key: target.PostgresFormat, + Description: "desc", + Type: "namespace*|access", + }, + { + Key: target.PostgresQueueDir, + Description: "des", + Optional: true, + Type: "path", + }, + { + Key: target.PostgresQueueLimit, + Description: "desc", + Optional: true, + Type: "number", + }, + { + Key: config.Comment, + Description: config.DefaultComment, + Optional: true, + Type: "sentence", + }, + } + mockConfigList := madmin.Help{ + SubSys: config.NotifyPostgresSubSys, + Description: "publish bucket notifications to Postgres databases", + MultipleTargets: true, + KeysHelp: configListMock, + } + // mock function response from listConfig() + minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) { + return mockConfigList, nil + } + }, + want: nil, + wantErr: true, + }, + { + name: "bad config", + args: args{ + client: client, + name: "notify_postgresx", + }, + mock: func() { + + // mock function response from getConfig() + minioGetConfigKVMock = func(key string) ([]byte, error) { + return nil, errors.New("Invalid config") + } + + mockConfigList := madmin.Help{} + // mock function response from listConfig() + minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) { + return mockConfigList, nil + } + }, + want: nil, + wantErr: true, + }, + { + name: "no help", + args: args{ + client: client, + name: "notify_postgresx", + }, + mock: func() { + // mock function response from getConfig() + minioGetConfigKVMock = func(key string) ([]byte, error) { + return nil, errors.New("Invalid config") + } + // mock function response from listConfig() + minioHelpConfigKVMock = func(subSys, key string, envOnly bool) (madmin.Help, error) { + return madmin.Help{}, errors.New("no help") + } + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + tt.mock() + t.Run(tt.name, func(t *testing.T) { + got, err := getConfig(tt.args.client, tt.args.name) + if (err != nil) != tt.wantErr { + t.Errorf("getConfig() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("getConfig() got = %v, want %v", got, tt.want) + } + }) + } +}