From a34887ca93d57665ce4c26ef7f1d787228783872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Palet?= Date: Tue, 18 Jun 2024 18:25:06 +0100 Subject: [PATCH 1/3] Extend sqlserverflex options command --- .../cmd/beta/sqlserverflex/options/options.go | 180 +++++++++-- .../sqlserverflex/options/options_test.go | 298 +++++++++++++----- 2 files changed, 388 insertions(+), 90 deletions(-) diff --git a/internal/cmd/beta/sqlserverflex/options/options.go b/internal/cmd/beta/sqlserverflex/options/options.go index 2e7fdf612..9cc420f8b 100644 --- a/internal/cmd/beta/sqlserverflex/options/options.go +++ b/internal/cmd/beta/sqlserverflex/options/options.go @@ -19,25 +19,38 @@ import ( ) const ( - flavorsFlag = "flavors" - versionsFlag = "versions" - storagesFlag = "storages" - flavorIdFlag = "flavor-id" + flavorsFlag = "flavors" + versionsFlag = "versions" + storagesFlag = "storages" + userRolesFlag = "user-roles" + dbCollationsFlag = "db-collations" + dbCompatibilitiesFlag = "db-compatibilities" + + flavorIdFlag = "flavor-id" + instanceIdFlag = "instance-id" ) type inputModel struct { *globalflags.GlobalFlagModel - Flavors bool - Versions bool - Storages bool - FlavorId *string + Flavors bool + Versions bool + Storages bool + UserRoles bool + DBCollations bool + DBCompatibilities bool + + FlavorId *string + InstanceId *string } type options struct { - Flavors *[]sqlserverflex.InstanceFlavorEntry `json:"flavors,omitempty"` - Versions *[]string `json:"versions,omitempty"` - Storages *flavorStorages `json:"flavorStorages,omitempty"` + Flavors *[]sqlserverflex.InstanceFlavorEntry `json:"flavors,omitempty"` + Versions *[]string `json:"versions,omitempty"` + Storages *flavorStorages `json:"flavorStorages,omitempty"` + UserRoles *instanceUserRoles `json:"userRoles,omitempty"` + DBCollations *instanceDBCollations `json:"dbCollations,omitempty"` + DBCompatibilities *instanceDBCompatibilities `json:"dbCompatibilities,omitempty"` } type flavorStorages struct { @@ -45,6 +58,21 @@ type flavorStorages struct { Storages *sqlserverflex.ListStoragesResponse `json:"storages"` } +type instanceUserRoles struct { + InstanceId string `json:"instanceId"` + UserRoles []string `json:"userRoles"` +} + +type instanceDBCollations struct { + InstanceId string `json:"instanceId"` + DBCollations []sqlserverflex.MssqlDatabaseCollation `json:"dbCollations"` +} + +type instanceDBCompatibilities struct { + InstanceId string `json:"instanceId"` + DBCompatibilities []sqlserverflex.MssqlDatabaseCompatibility `json:"dbCompatibilities"` +} + func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "options", @@ -92,17 +120,27 @@ func configureFlags(cmd *cobra.Command) { cmd.Flags().Bool(flavorsFlag, false, "Lists supported flavors") cmd.Flags().Bool(versionsFlag, false, "Lists supported versions") cmd.Flags().Bool(storagesFlag, false, "Lists supported storages for a given flavor") + cmd.Flags().Bool(userRolesFlag, false, "Lists supported user roles for a given instance") + cmd.Flags().Bool(dbCollationsFlag, false, "Lists supported database collations for a given instance") + cmd.Flags().Bool(dbCompatibilitiesFlag, false, "Lists supported database compatibilities for a given instance") cmd.Flags().String(flavorIdFlag, "", `The flavor ID to show storages for. Only relevant when "--storages" is passed`) + cmd.Flags().String(instanceIdFlag, "", `The instance ID to show user roles, database collations and database compatibilities for. Only relevant when "--user-roles", "--db-collations" or "--db-compatibilities" is passed`) } func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { globalFlags := globalflags.Parse(p, cmd) + flavors := flags.FlagToBoolValue(p, cmd, flavorsFlag) versions := flags.FlagToBoolValue(p, cmd, versionsFlag) storages := flags.FlagToBoolValue(p, cmd, storagesFlag) + userRoles := flags.FlagToBoolValue(p, cmd, userRolesFlag) + dbCollations := flags.FlagToBoolValue(p, cmd, dbCollationsFlag) + dbCompatibilities := flags.FlagToBoolValue(p, cmd, dbCompatibilitiesFlag) + flavorId := flags.FlagToStringPointer(p, cmd, flavorIdFlag) + instanceId := flags.FlagToStringPointer(p, cmd, instanceIdFlag) - if !flavors && !versions && !storages { + if !flavors && !versions && !storages && !userRoles && !dbCollations && !dbCompatibilities { return nil, fmt.Errorf("%s\n\n%s", "please specify at least one category for which to list the available options.", "Get details on the available flags by re-running your command with the --help flag.") @@ -115,12 +153,23 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { " $ stackit sqlserverflex options --flavors") } + if (userRoles || dbCollations || dbCompatibilities) && instanceId == nil { + return nil, fmt.Errorf("%s\n\n%s\n%s", + `please specify an instance ID to show user roles, database collations or database compatibilities for by setting the flag "--instance-id ".`, + "You can get the available instances and their IDs by running:", + " $ stackit sqlserverflex instance list") + } + model := inputModel{ - GlobalFlagModel: globalFlags, - Flavors: flavors, - Versions: versions, - Storages: storages, - FlavorId: flags.FlagToStringPointer(p, cmd, flavorIdFlag), + GlobalFlagModel: globalFlags, + Flavors: flavors, + Versions: versions, + Storages: storages, + UserRoles: userRoles, + DBCollations: dbCollations, + DBCompatibilities: dbCompatibilities, + FlavorId: flavorId, + InstanceId: instanceId, } if p.IsVerbosityDebug() { @@ -139,12 +188,18 @@ type sqlServerFlexOptionsClient interface { ListFlavorsExecute(ctx context.Context, projectId string) (*sqlserverflex.ListFlavorsResponse, error) ListVersionsExecute(ctx context.Context, projectId string) (*sqlserverflex.ListVersionsResponse, error) ListStoragesExecute(ctx context.Context, projectId, flavorId string) (*sqlserverflex.ListStoragesResponse, error) + ListRolesExecute(ctx context.Context, projectId string, instanceId string) (*sqlserverflex.ListRolesResponse, error) + ListCollationsExecute(ctx context.Context, projectId string, instanceId string) (*sqlserverflex.ListCollationsResponse, error) + ListCompatibilityExecute(ctx context.Context, projectId string, instanceId string) (*sqlserverflex.ListCompatibilityResponse, error) } func buildAndExecuteRequest(ctx context.Context, p *print.Printer, model *inputModel, apiClient sqlServerFlexOptionsClient) error { var flavors *sqlserverflex.ListFlavorsResponse var versions *sqlserverflex.ListVersionsResponse var storages *sqlserverflex.ListStoragesResponse + var userRoles *sqlserverflex.ListRolesResponse + var dbCollations *sqlserverflex.ListCollationsResponse + var dbCompatibilities *sqlserverflex.ListCompatibilityResponse var err error if model.Flavors { @@ -165,11 +220,29 @@ func buildAndExecuteRequest(ctx context.Context, p *print.Printer, model *inputM return fmt.Errorf("get SQL Server Flex storages: %w", err) } } + if model.UserRoles { + userRoles, err = apiClient.ListRolesExecute(ctx, model.ProjectId, *model.InstanceId) + if err != nil { + return fmt.Errorf("get SQL Server Flex user roles: %w", err) + } + } + if model.DBCollations { + dbCollations, err = apiClient.ListCollationsExecute(ctx, model.ProjectId, *model.InstanceId) + if err != nil { + return fmt.Errorf("get SQL Server Flex DB collations: %w", err) + } + } + if model.DBCompatibilities { + dbCompatibilities, err = apiClient.ListCompatibilityExecute(ctx, model.ProjectId, *model.InstanceId) + if err != nil { + return fmt.Errorf("get SQL Server Flex DB compatibilities: %w", err) + } + } - return outputResult(p, model, flavors, versions, storages) + return outputResult(p, model, flavors, versions, storages, userRoles, dbCollations, dbCompatibilities) } -func outputResult(p *print.Printer, model *inputModel, flavors *sqlserverflex.ListFlavorsResponse, versions *sqlserverflex.ListVersionsResponse, storages *sqlserverflex.ListStoragesResponse) error { +func outputResult(p *print.Printer, model *inputModel, flavors *sqlserverflex.ListFlavorsResponse, versions *sqlserverflex.ListVersionsResponse, storages *sqlserverflex.ListStoragesResponse, userRoles *sqlserverflex.ListRolesResponse, dbCollations *sqlserverflex.ListCollationsResponse, dbCompatibilities *sqlserverflex.ListCompatibilityResponse) error { options := &options{} if flavors != nil { options.Flavors = flavors.Flavors @@ -183,6 +256,24 @@ func outputResult(p *print.Printer, model *inputModel, flavors *sqlserverflex.Li Storages: storages, } } + if userRoles != nil && model.InstanceId != nil { + options.UserRoles = &instanceUserRoles{ + InstanceId: *model.InstanceId, + UserRoles: *userRoles.Roles, + } + } + if dbCollations != nil && model.InstanceId != nil { + options.DBCollations = &instanceDBCollations{ + InstanceId: *model.InstanceId, + DBCollations: *dbCollations.Collations, + } + } + if dbCompatibilities != nil && model.InstanceId != nil { + options.DBCompatibilities = &instanceDBCompatibilities{ + InstanceId: *model.InstanceId, + DBCompatibilities: *dbCompatibilities.Compatibilities, + } + } switch model.OutputFormat { case print.JSONOutputFormat: @@ -216,6 +307,15 @@ func outputResultAsTable(p *print.Printer, model *inputModel, options *options) if model.Storages { content += renderStorages(options.Storages.Storages) } + if model.UserRoles { + content += renderUserRoles(options.UserRoles) + } + if model.DBCollations { + content += renderDBCollations(options.DBCollations) + } + if model.DBCompatibilities { + content += renderDBCompatibilities(options.DBCompatibilities) + } err := p.PagerDisplay(content) if err != nil { @@ -271,3 +371,45 @@ func renderStorages(resp *sqlserverflex.ListStoragesResponse) string { table.EnableAutoMergeOnColumns(1, 2, 3) return table.Render() } + +func renderUserRoles(roles *instanceUserRoles) string { + if len(roles.UserRoles) == 0 { + return "" + } + + table := tables.NewTable() + table.SetTitle("User Roles") + table.SetHeader("ROLE") + for i := range roles.UserRoles { + table.AddRow(roles.UserRoles[i]) + } + return table.Render() +} + +func renderDBCollations(dbCollations *instanceDBCollations) string { + if len(dbCollations.DBCollations) == 0 { + return "" + } + + table := tables.NewTable() + table.SetTitle("DB Collations") + table.SetHeader("NAME", "DESCRIPTION") + for i := range dbCollations.DBCollations { + table.AddRow(*dbCollations.DBCollations[i].CollationName, *dbCollations.DBCollations[i].Description) + } + return table.Render() +} + +func renderDBCompatibilities(dbCompatibilities *instanceDBCompatibilities) string { + if len(dbCompatibilities.DBCompatibilities) == 0 { + return "" + } + + table := tables.NewTable() + table.SetTitle("DB Compatibilities") + table.SetHeader("COMPATIBILITY LEVEL", "DESCRIPTION") + for i := range dbCompatibilities.DBCompatibilities { + table.AddRow(*dbCompatibilities.DBCompatibilities[i].CompatibilityLevel, *dbCompatibilities.DBCompatibilities[i].Description) + } + return table.Render() +} diff --git a/internal/cmd/beta/sqlserverflex/options/options_test.go b/internal/cmd/beta/sqlserverflex/options/options_test.go index bece7beb0..c497ae3ac 100644 --- a/internal/cmd/beta/sqlserverflex/options/options_test.go +++ b/internal/cmd/beta/sqlserverflex/options/options_test.go @@ -10,21 +10,29 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/google/go-cmp/cmp" + "github.com/google/uuid" "github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex" ) type testCtxKey struct{} var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") +var testInstanceId = uuid.NewString() type sqlServerFlexClientMocked struct { - listFlavorsFails bool - listVersionsFails bool - listStoragesFails bool + listFlavorsFails bool + listVersionsFails bool + listStoragesFails bool + listUserRolesFails bool + listDBCollationsFails bool + listDBCompatibilitiesFails bool - listFlavorsCalled bool - listVersionsCalled bool - listStoragesCalled bool + listFlavorsCalled bool + listVersionsCalled bool + listStoragesCalled bool + listUserRolesCalled bool + listDBCollationsCalled bool + listDBCompatibilitiesCalled bool } func (c *sqlServerFlexClientMocked) ListFlavorsExecute(_ context.Context, _ string) (*sqlserverflex.ListFlavorsResponse, error) { @@ -61,12 +69,46 @@ func (c *sqlServerFlexClientMocked) ListStoragesExecute(_ context.Context, _, _ }), nil } +func (c *sqlServerFlexClientMocked) ListRolesExecute(_ context.Context, _, _ string) (*sqlserverflex.ListRolesResponse, error) { + c.listUserRolesCalled = true + if c.listUserRolesFails { + return nil, fmt.Errorf("list roles failed") + } + return utils.Ptr(sqlserverflex.ListRolesResponse{ + Roles: utils.Ptr([]string{}), + }), nil +} + +func (c *sqlServerFlexClientMocked) ListCollationsExecute(_ context.Context, _, _ string) (*sqlserverflex.ListCollationsResponse, error) { + c.listDBCollationsCalled = true + if c.listDBCollationsFails { + return nil, fmt.Errorf("list collations failed") + } + return utils.Ptr(sqlserverflex.ListCollationsResponse{ + Collations: utils.Ptr([]sqlserverflex.MssqlDatabaseCollation{}), + }), nil +} + +func (c *sqlServerFlexClientMocked) ListCompatibilityExecute(_ context.Context, _, _ string) (*sqlserverflex.ListCompatibilityResponse, error) { + c.listDBCompatibilitiesCalled = true + if c.listDBCompatibilitiesFails { + return nil, fmt.Errorf("list compatibilities failed") + } + return utils.Ptr(sqlserverflex.ListCompatibilityResponse{ + Compatibilities: utils.Ptr([]sqlserverflex.MssqlDatabaseCompatibility{}), + }), nil +} + func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ - flavorsFlag: "true", - versionsFlag: "true", - storagesFlag: "true", - flavorIdFlag: "2.4", + flavorsFlag: "true", + versionsFlag: "true", + storagesFlag: "true", + userRolesFlag: "true", + dbCollationsFlag: "true", + dbCompatibilitiesFlag: "true", + flavorIdFlag: "2.4", + instanceIdFlag: testInstanceId, } for _, mod := range mods { mod(flagValues) @@ -76,10 +118,13 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st func fixtureInputModelAllFalse(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{Verbosity: globalflags.VerbosityDefault}, - Flavors: false, - Versions: false, - Storages: false, + GlobalFlagModel: &globalflags.GlobalFlagModel{Verbosity: globalflags.VerbosityDefault}, + Flavors: false, + Versions: false, + Storages: false, + UserRoles: false, + DBCollations: false, + DBCompatibilities: false, } for _, mod := range mods { mod(model) @@ -89,11 +134,15 @@ func fixtureInputModelAllFalse(mods ...func(model *inputModel)) *inputModel { func fixtureInputModelAllTrue(mods ...func(model *inputModel)) *inputModel { model := &inputModel{ - GlobalFlagModel: &globalflags.GlobalFlagModel{Verbosity: globalflags.VerbosityDefault}, - Flavors: true, - Versions: true, - Storages: true, - FlavorId: utils.Ptr("2.4"), + GlobalFlagModel: &globalflags.GlobalFlagModel{Verbosity: globalflags.VerbosityDefault}, + Flavors: true, + Versions: true, + Storages: true, + UserRoles: true, + DBCollations: true, + DBCompatibilities: true, + FlavorId: utils.Ptr("2.4"), + InstanceId: utils.Ptr(testInstanceId), } for _, mod := range mods { mod(model) @@ -126,9 +175,9 @@ func TestParseInput(t *testing.T) { delete(flagValues, flavorIdFlag) }), isValid: true, - expectedModel: fixtureInputModelAllFalse(func(model *inputModel) { - model.Flavors = true - model.Versions = true + expectedModel: fixtureInputModelAllTrue(func(model *inputModel) { + model.Storages = false + model.FlavorId = nil }), }, { @@ -136,13 +185,15 @@ func TestParseInput(t *testing.T) { flagValues: fixtureFlagValues(func(flagValues map[string]string) { delete(flagValues, flavorsFlag) delete(flagValues, versionsFlag) + delete(flagValues, userRolesFlag) flagValues[storagesFlag] = "true" flagValues[flavorIdFlag] = "2.4" }), isValid: true, - expectedModel: fixtureInputModelAllFalse(func(model *inputModel) { - model.Storages = true - model.FlavorId = utils.Ptr("2.4") + expectedModel: fixtureInputModelAllTrue(func(model *inputModel) { + model.Flavors = false + model.Versions = false + model.UserRoles = false }), }, { @@ -162,6 +213,23 @@ func TestParseInput(t *testing.T) { model.Storages = false }), }, + { + description: "user roles without instance id", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, instanceIdFlag) + }), + isValid: false, + }, + { + description: "instance id without user roles", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, userRolesFlag) + }), + isValid: true, + expectedModel: fixtureInputModelAllTrue(func(model *inputModel) { + model.UserRoles = false + }), + }, } for _, tt := range tests { @@ -212,31 +280,44 @@ func TestParseInput(t *testing.T) { func TestBuildAndExecuteRequest(t *testing.T) { tests := []struct { - description string - model *inputModel - isValid bool - listFlavorsFails bool - listVersionsFails bool - listStoragesFails bool - expectListFlavorsCalled bool - expectListVersionsCalled bool - expectListStoragesCalled bool + description string + model *inputModel + isValid bool + listFlavorsFails bool + listVersionsFails bool + listStoragesFails bool + listUserRolesFails bool + listDBCollationsFails bool + listDBCompatibilitiesFails bool + + expectListFlavorsCalled bool + expectListVersionsCalled bool + expectListStoragesCalled bool + expectListUserRolesCalled bool + expectListDBCollationsCalled bool + expectListDBCompatibilitiesCalled bool }{ { - description: "all values", - model: fixtureInputModelAllTrue(), - isValid: true, - expectListFlavorsCalled: true, - expectListVersionsCalled: true, - expectListStoragesCalled: true, + description: "all values", + model: fixtureInputModelAllTrue(), + isValid: true, + expectListFlavorsCalled: true, + expectListVersionsCalled: true, + expectListStoragesCalled: true, + expectListUserRolesCalled: true, + expectListDBCollationsCalled: true, + expectListDBCompatibilitiesCalled: true, }, { - description: "no values", - model: fixtureInputModelAllFalse(), - isValid: true, - expectListFlavorsCalled: false, - expectListVersionsCalled: false, - expectListStoragesCalled: false, + description: "no values", + model: fixtureInputModelAllFalse(), + isValid: true, + expectListFlavorsCalled: false, + expectListVersionsCalled: false, + expectListStoragesCalled: false, + expectListUserRolesCalled: false, + expectListDBCollationsCalled: false, + expectListDBCompatibilitiesCalled: false, }, { description: "only flavors", @@ -260,43 +341,118 @@ func TestBuildAndExecuteRequest(t *testing.T) { expectListStoragesCalled: true, }, { - description: "list flavors fails", - model: fixtureInputModelAllTrue(), - isValid: false, - listFlavorsFails: true, - expectListFlavorsCalled: true, - expectListVersionsCalled: false, - expectListStoragesCalled: false, + description: "only user roles", + model: fixtureInputModelAllFalse(func(model *inputModel) { + model.UserRoles = true + model.InstanceId = utils.Ptr(testInstanceId) + }), + isValid: true, + expectListUserRolesCalled: true, }, { - description: "list versions fails", - model: fixtureInputModelAllTrue(), - isValid: false, - listVersionsFails: true, - expectListFlavorsCalled: true, - expectListVersionsCalled: true, - expectListStoragesCalled: false, + description: "only db collations", + model: fixtureInputModelAllFalse(func(model *inputModel) { + model.DBCollations = true + model.InstanceId = utils.Ptr(testInstanceId) + }), + isValid: true, + expectListDBCollationsCalled: true, }, { - description: "list storages fails", - model: fixtureInputModelAllTrue(), - isValid: false, - listStoragesFails: true, - expectListFlavorsCalled: true, - expectListVersionsCalled: true, - expectListStoragesCalled: true, + description: "only db compatibilities", + model: fixtureInputModelAllFalse(func(model *inputModel) { + model.DBCompatibilities = true + model.InstanceId = utils.Ptr(testInstanceId) + }), + isValid: true, + expectListDBCompatibilitiesCalled: true, + }, + { + description: "list flavors fails", + model: fixtureInputModelAllTrue(), + isValid: false, + listFlavorsFails: true, + expectListFlavorsCalled: true, + expectListVersionsCalled: false, + expectListStoragesCalled: false, + expectListUserRolesCalled: false, + expectListDBCollationsCalled: false, + expectListDBCompatibilitiesCalled: false, + }, + { + description: "list versions fails", + model: fixtureInputModelAllTrue(), + isValid: false, + listVersionsFails: true, + expectListFlavorsCalled: true, + expectListVersionsCalled: true, + expectListStoragesCalled: false, + expectListUserRolesCalled: false, + expectListDBCollationsCalled: false, + expectListDBCompatibilitiesCalled: false, + }, + { + description: "list storages fails", + model: fixtureInputModelAllTrue(), + isValid: false, + listStoragesFails: true, + expectListFlavorsCalled: true, + expectListVersionsCalled: true, + expectListStoragesCalled: true, + expectListUserRolesCalled: false, + expectListDBCollationsCalled: false, + expectListDBCompatibilitiesCalled: false, + }, + { + description: "list user roles fails", + model: fixtureInputModelAllTrue(), + isValid: false, + listUserRolesFails: true, + expectListFlavorsCalled: true, + expectListVersionsCalled: true, + expectListStoragesCalled: true, + expectListUserRolesCalled: true, + expectListDBCollationsCalled: false, + expectListDBCompatibilitiesCalled: false, + }, + { + description: "list db collations fails", + model: fixtureInputModelAllTrue(), + isValid: false, + listDBCollationsFails: true, + expectListFlavorsCalled: true, + expectListVersionsCalled: true, + expectListStoragesCalled: true, + expectListUserRolesCalled: true, + expectListDBCollationsCalled: true, + expectListDBCompatibilitiesCalled: false, + }, + { + description: "list db compatibilities fails", + model: fixtureInputModelAllTrue(), + isValid: false, + listDBCompatibilitiesFails: true, + expectListFlavorsCalled: true, + expectListVersionsCalled: true, + expectListStoragesCalled: true, + expectListUserRolesCalled: true, + expectListDBCollationsCalled: true, + expectListDBCompatibilitiesCalled: true, }, } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - p := &print.Printer{} + p := print.NewPrinter() cmd := NewCmd(p) p.Cmd = cmd client := &sqlServerFlexClientMocked{ - listFlavorsFails: tt.listFlavorsFails, - listVersionsFails: tt.listVersionsFails, - listStoragesFails: tt.listStoragesFails, + listFlavorsFails: tt.listFlavorsFails, + listVersionsFails: tt.listVersionsFails, + listStoragesFails: tt.listStoragesFails, + listUserRolesFails: tt.listUserRolesFails, + listDBCollationsFails: tt.listDBCollationsFails, + listDBCompatibilitiesFails: tt.listDBCompatibilitiesFails, } err := buildAndExecuteRequest(testCtx, p, tt.model, client) From b13638a0c15d00fbcb959ea5383e30b9b6d85311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Palet?= Date: Tue, 18 Jun 2024 18:25:24 +0100 Subject: [PATCH 2/3] Update docs --- docs/stackit_beta_sqlserverflex_options.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/stackit_beta_sqlserverflex_options.md b/docs/stackit_beta_sqlserverflex_options.md index 6f53cf23a..f55a6f2ff 100644 --- a/docs/stackit_beta_sqlserverflex_options.md +++ b/docs/stackit_beta_sqlserverflex_options.md @@ -27,11 +27,15 @@ stackit beta sqlserverflex options [flags] ### Options ``` - --flavor-id string The flavor ID to show storages for. Only relevant when "--storages" is passed - --flavors Lists supported flavors - -h, --help Help for "stackit beta sqlserverflex options" - --storages Lists supported storages for a given flavor - --versions Lists supported versions + --db-collations Lists supported database collations for a given instance + --db-compatibilities Lists supported database compatibilities for a given instance + --flavor-id string The flavor ID to show storages for. Only relevant when "--storages" is passed + --flavors Lists supported flavors + -h, --help Help for "stackit beta sqlserverflex options" + --instance-id string The instance ID to show user roles, database collations and database compatibilities for. Only relevant when "--user-roles", "--db-collations" or "--db-compatibilities" is passed + --storages Lists supported storages for a given flavor + --user-roles Lists supported user roles for a given instance + --versions Lists supported versions ``` ### Options inherited from parent commands From e0e33ea56753bc09e75f0ec2172acf81bc6fd418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Palet?= Date: Wed, 19 Jun 2024 10:49:00 +0100 Subject: [PATCH 3/3] Improve test --- .../sqlserverflex/options/options_test.go | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/internal/cmd/beta/sqlserverflex/options/options_test.go b/internal/cmd/beta/sqlserverflex/options/options_test.go index c497ae3ac..02aff416b 100644 --- a/internal/cmd/beta/sqlserverflex/options/options_test.go +++ b/internal/cmd/beta/sqlserverflex/options/options_test.go @@ -217,17 +217,41 @@ func TestParseInput(t *testing.T) { description: "user roles without instance id", flagValues: fixtureFlagValues(func(flagValues map[string]string) { delete(flagValues, instanceIdFlag) + delete(flagValues, dbCollationsFlag) + delete(flagValues, dbCompatibilitiesFlag) }), isValid: false, }, { - description: "instance id without user roles", + description: "db collations without instance id", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, instanceIdFlag) + delete(flagValues, userRolesFlag) + delete(flagValues, dbCompatibilitiesFlag) + }), + isValid: false, + }, + { + description: "db compatibilities without instance id", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, instanceIdFlag) + delete(flagValues, userRolesFlag) + delete(flagValues, dbCollationsFlag) + }), + isValid: false, + }, + { + description: "instance id without user roles, db collations and db compatibilities", flagValues: fixtureFlagValues(func(flagValues map[string]string) { delete(flagValues, userRolesFlag) + delete(flagValues, dbCollationsFlag) + delete(flagValues, dbCompatibilitiesFlag) }), isValid: true, expectedModel: fixtureInputModelAllTrue(func(model *inputModel) { model.UserRoles = false + model.DBCollations = false + model.DBCompatibilities = false }), }, }