diff --git a/internal/cmd/redis/credentials/create/create.go b/internal/cmd/redis/credentials/create/create.go index 388e269a4..9b2098344 100644 --- a/internal/cmd/redis/credentials/create/create.go +++ b/internal/cmd/redis/credentials/create/create.go @@ -79,7 +79,7 @@ func NewCmd(p *print.Printer) *cobra.Command { return fmt.Errorf("create Redis credentials: %w", err) } - return outputResult(p, model, instanceLabel, resp) + return outputResult(p, *model, instanceLabel, resp) }, } configureFlags(cmd) @@ -123,8 +123,20 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *redis.APICl return req } -func outputResult(p *print.Printer, model *inputModel, instanceLabel string, resp *redis.CredentialsResponse) error { +func outputResult(p *print.Printer, model inputModel, instanceLabel string, resp *redis.CredentialsResponse) error { + if model.GlobalFlagModel == nil { + return fmt.Errorf("no global flags defined") + } + if resp == nil { + return fmt.Errorf("no response defined") + } if !model.ShowPassword { + if resp.Raw == nil { + resp.Raw = &redis.RawCredentials{} + } + if resp.Raw.Credentials == nil { + resp.Raw.Credentials = &redis.Credentials{} + } resp.Raw.Credentials.Password = utils.Ptr("hidden") } @@ -146,11 +158,11 @@ func outputResult(p *print.Printer, model *inputModel, instanceLabel string, res return nil default: - p.Outputf("Created credentials for instance %q. Credentials ID: %s\n\n", instanceLabel, *resp.Id) + p.Outputf("Created credentials for instance %q. Credentials ID: %s\n\n", instanceLabel, utils.PtrString(resp.Id)) // The username field cannot be set by the user, so we only display it if it's not returned empty if resp.HasRaw() && resp.Raw.Credentials != nil { if username := resp.Raw.Credentials.Username; username != nil && *username != "" { - p.Outputf("Username: %s\n", *username) + p.Outputf("Username: %s\n", utils.PtrString(username)) } if !model.ShowPassword { p.Outputf("Password: \n") diff --git a/internal/cmd/redis/credentials/create/create_test.go b/internal/cmd/redis/credentials/create/create_test.go index bb1ee454a..511b066ad 100644 --- a/internal/cmd/redis/credentials/create/create_test.go +++ b/internal/cmd/redis/credentials/create/create_test.go @@ -4,12 +4,11 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-sdk-go/services/redis" ) @@ -200,3 +199,36 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + model inputModel + instanceLabel string + resp *redis.CredentialsResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{model: inputModel{GlobalFlagModel: &globalflags.GlobalFlagModel{}}, resp: &redis.CredentialsResponse{}}, + wantErr: false, + }, + { + name: "nil response", + args: args{model: inputModel{GlobalFlagModel: &globalflags.GlobalFlagModel{}}}, + wantErr: true, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(p) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.model, tt.args.instanceLabel, tt.args.resp); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/redis/credentials/describe/describe.go b/internal/cmd/redis/credentials/describe/describe.go index 6d342002f..7a6dc78e4 100644 --- a/internal/cmd/redis/credentials/describe/describe.go +++ b/internal/cmd/redis/credentials/describe/describe.go @@ -112,6 +112,9 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *redis.APICl } func outputResult(p *print.Printer, outputFormat string, credentials *redis.CredentialsResponse) error { + if credentials == nil { + return fmt.Errorf("no credentials passed") + } switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(credentials, "", " ") @@ -131,7 +134,7 @@ func outputResult(p *print.Printer, outputFormat string, credentials *redis.Cred return nil default: table := tables.NewTable() - table.AddRow("ID", *credentials.Id) + table.AddRow("ID", utils.PtrString(credentials.Id)) table.AddSeparator() // The username field cannot be set by the user so we only display it if it's not returned empty if credentials.HasRaw() && credentials.Raw.Credentials != nil { diff --git a/internal/cmd/redis/credentials/describe/describe_test.go b/internal/cmd/redis/credentials/describe/describe_test.go index 909d337f4..c6f837491 100644 --- a/internal/cmd/redis/credentials/describe/describe_test.go +++ b/internal/cmd/redis/credentials/describe/describe_test.go @@ -4,12 +4,11 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-sdk-go/services/redis" ) @@ -243,3 +242,37 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + credentials *redis.CredentialsResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{ + credentials: &redis.CredentialsResponse{}, + }, + wantErr: false, + }, + { + name: "nil response", + args: args{}, + wantErr: true, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(p) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.outputFormat, tt.args.credentials); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/redis/credentials/list/list_test.go b/internal/cmd/redis/credentials/list/list_test.go index d59fc9c80..b771823bf 100644 --- a/internal/cmd/redis/credentials/list/list_test.go +++ b/internal/cmd/redis/credentials/list/list_test.go @@ -4,13 +4,12 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/redis" ) @@ -207,3 +206,40 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + credentials []redis.CredentialsListItem + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{}, + wantErr: false, + }, + { + name: "slice with empty element", + args: args{ + outputFormat: "", + credentials: []redis.CredentialsListItem{ + {}, + }, + }, + wantErr: false, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(p) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.outputFormat, tt.args.credentials); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/redis/instance/create/create.go b/internal/cmd/redis/instance/create/create.go index 84d8e19ee..87db67741 100644 --- a/internal/cmd/redis/instance/create/create.go +++ b/internal/cmd/redis/instance/create/create.go @@ -252,6 +252,15 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient redisClient) } func outputResult(p *print.Printer, model *inputModel, projectLabel, instanceId string, resp *redis.CreateInstanceResponse) error { + if model == nil { + return fmt.Errorf("no model passed") + } + if model.GlobalFlagModel == nil { + return fmt.Errorf("no global flags passed") + } + if resp == nil { + return fmt.Errorf("no response defined") + } switch model.OutputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(resp, "", " ") diff --git a/internal/cmd/redis/instance/create/create_test.go b/internal/cmd/redis/instance/create/create_test.go index dd35d51be..59ee4d259 100644 --- a/internal/cmd/redis/instance/create/create_test.go +++ b/internal/cmd/redis/instance/create/create_test.go @@ -5,13 +5,12 @@ import ( "fmt" "testing" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/redis" ) @@ -463,3 +462,46 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + model *inputModel + projectLabel string + instanceId string + resp *redis.CreateInstanceResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{ + model: &inputModel{GlobalFlagModel: &globalflags.GlobalFlagModel{}}, + projectLabel: "", + instanceId: testMonitoringInstanceId, + resp: &redis.CreateInstanceResponse{}, + }, + wantErr: false, + }, + { + name: "nil response", + args: args{ + model: &inputModel{GlobalFlagModel: &globalflags.GlobalFlagModel{}}, + projectLabel: "", + instanceId: testMonitoringInstanceId, + }, + wantErr: true, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(p) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.model, tt.args.projectLabel, tt.args.instanceId, tt.args.resp); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/redis/instance/describe/describe.go b/internal/cmd/redis/instance/describe/describe.go index 5e8737212..f91b4b1e6 100644 --- a/internal/cmd/redis/instance/describe/describe.go +++ b/internal/cmd/redis/instance/describe/describe.go @@ -100,6 +100,9 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *redis.APICl } func outputResult(p *print.Printer, outputFormat string, instance *redis.Instance) error { + if instance == nil { + return fmt.Errorf("no instance passed") + } switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(instance, "", " ") @@ -123,18 +126,22 @@ func outputResult(p *print.Printer, outputFormat string, instance *redis.Instanc table.AddSeparator() table.AddRow("NAME", utils.PtrString(instance.Name)) table.AddSeparator() - table.AddRow("LAST OPERATION TYPE", utils.PtrString(instance.LastOperation.Type)) - table.AddSeparator() - table.AddRow("LAST OPERATION STATE", utils.PtrString(instance.LastOperation.State)) - table.AddSeparator() + if lastOperation := instance.LastOperation; lastOperation != nil { + table.AddRow("LAST OPERATION TYPE", utils.PtrString(instance.LastOperation.Type)) + table.AddSeparator() + table.AddRow("LAST OPERATION STATE", utils.PtrString(instance.LastOperation.State)) + table.AddSeparator() + } table.AddRow("PLAN ID", utils.PtrString(instance.PlanId)) - // Only show ACL if it's present and not empty - acl := (*instance.Parameters)[aclParameterKey] - aclStr, ok := acl.(string) - if ok { - if aclStr != "" { - table.AddSeparator() - table.AddRow("ACL", aclStr) + if parameters := instance.Parameters; parameters != nil { + // Only show ACL if it's present and not empty + acl := (*parameters)[aclParameterKey] + aclStr, ok := acl.(string) + if ok { + if aclStr != "" { + table.AddSeparator() + table.AddRow("ACL", aclStr) + } } } err := table.Display(p) diff --git a/internal/cmd/redis/instance/describe/describe_test.go b/internal/cmd/redis/instance/describe/describe_test.go index 188927f28..1e12d6195 100644 --- a/internal/cmd/redis/instance/describe/describe_test.go +++ b/internal/cmd/redis/instance/describe/describe_test.go @@ -4,12 +4,11 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-sdk-go/services/redis" ) @@ -216,3 +215,48 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + instance *redis.Instance + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{ + instance: &redis.Instance{}, + }, + wantErr: false, + }, + { + name: "nil response", + args: args{}, + wantErr: true, + }, + { + name: "nil parameter", + args: args{ + instance: &redis.Instance{ + Parameters: &map[string]interface{}{ + "foo": nil, + }, + }, + }, + wantErr: false, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(p) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.outputFormat, tt.args.instance); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/redis/instance/list/list.go b/internal/cmd/redis/instance/list/list.go index d75ea93b4..4b49c15fa 100644 --- a/internal/cmd/redis/instance/list/list.go +++ b/internal/cmd/redis/instance/list/list.go @@ -152,11 +152,17 @@ func outputResult(p *print.Printer, outputFormat string, instances []redis.Insta table.SetHeader("ID", "NAME", "LAST OPERATION TYPE", "LAST OPERATION STATE") for i := range instances { instance := instances[i] + var ( + lastOperationType, lastOperationState string + ) + if lastOperation := instance.LastOperation; lastOperation != nil { + lastOperationType, lastOperationState = utils.PtrString(lastOperation.Type), utils.PtrString(lastOperation.State) + } table.AddRow( utils.PtrString(instance.InstanceId), utils.PtrString(instance.Name), - utils.PtrString(instance.LastOperation.Type), - utils.PtrString(instance.LastOperation.State), + lastOperationType, + lastOperationState, ) } err := table.Display(p) diff --git a/internal/cmd/redis/instance/list/list_test.go b/internal/cmd/redis/instance/list/list_test.go index 692c71222..0338bd8a7 100644 --- a/internal/cmd/redis/instance/list/list_test.go +++ b/internal/cmd/redis/instance/list/list_test.go @@ -4,14 +4,13 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" "github.com/spf13/cobra" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/redis" ) @@ -186,3 +185,39 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + instances []redis.Instance + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{}, + wantErr: false, + }, + { + name: "slice with empty element", + args: args{ + instances: []redis.Instance{ + {}, + }, + }, + wantErr: false, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(p) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.outputFormat, tt.args.instances); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/redis/plans/plans.go b/internal/cmd/redis/plans/plans.go index 0f7dbde6b..8ae785da6 100644 --- a/internal/cmd/redis/plans/plans.go +++ b/internal/cmd/redis/plans/plans.go @@ -152,17 +152,19 @@ func outputResult(p *print.Printer, outputFormat string, plans []redis.Offering) table.SetHeader("OFFERING NAME", "VERSION", "ID", "NAME", "DESCRIPTION") for i := range plans { o := plans[i] - for j := range *o.Plans { - plan := (*o.Plans)[j] - table.AddRow( - utils.PtrString(o.Name), - utils.PtrString(o.Version), - utils.PtrString(plan.Id), - utils.PtrString(plan.Name), - utils.PtrString(plan.Description), - ) + if o.Plans != nil { + for j := range *o.Plans { + plan := (*o.Plans)[j] + table.AddRow( + utils.PtrString(o.Name), + utils.PtrString(o.Version), + utils.PtrString(plan.Id), + utils.PtrString(plan.Name), + utils.PtrString(plan.Description), + ) + } + table.AddSeparator() } - table.AddSeparator() } table.EnableAutoMergeOnColumns(1, 2) err := table.Display(p) diff --git a/internal/cmd/redis/plans/plans_test.go b/internal/cmd/redis/plans/plans_test.go index 7f1a7a909..f850de8a1 100644 --- a/internal/cmd/redis/plans/plans_test.go +++ b/internal/cmd/redis/plans/plans_test.go @@ -4,14 +4,13 @@ import ( "context" "testing" - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" "github.com/spf13/cobra" + "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "github.com/stackitcloud/stackit-sdk-go/services/redis" ) @@ -186,3 +185,39 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + plans []redis.Offering + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "empty", + args: args{}, + wantErr: false, + }, + { + name: "slice with empty elements", + args: args{ + plans: []redis.Offering{ + {}, + }, + }, + wantErr: false, + }, + } + p := print.NewPrinter() + p.Cmd = NewCmd(p) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := outputResult(p, tt.args.outputFormat, tt.args.plans); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +}