diff --git a/internal/cmd/postgresflex/backup/describe/describe.go b/internal/cmd/postgresflex/backup/describe/describe.go index 80cae356a..32cee719f 100644 --- a/internal/cmd/postgresflex/backup/describe/describe.go +++ b/internal/cmd/postgresflex/backup/describe/describe.go @@ -72,7 +72,7 @@ func NewCmd(p *print.Printer) *cobra.Command { return fmt.Errorf("describe backup for PostgreSQL Flex instance: %w", err) } - return outputResult(p, cmd, model.OutputFormat, *resp.Item) + return outputResult(p, model.OutputFormat, *resp.Item) }, } configureFlags(cmd) @@ -106,8 +106,11 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *postgresfle return req } -func outputResult(p *print.Printer, cmd *cobra.Command, outputFormat string, backup postgresflex.Backup) error { - backupStartTime, err := time.Parse(time.RFC3339, *backup.StartTime) +func outputResult(p *print.Printer, outputFormat string, backup postgresflex.Backup) error { + if backup.StartTime == nil || *backup.StartTime == "" { + return fmt.Errorf("start time not defined") + } + backupStartTime, err := time.Parse(time.RFC3339, utils.PtrString(backup.StartTime)) if err != nil { return fmt.Errorf("parse backup start time: %w", err) } @@ -119,7 +122,7 @@ func outputResult(p *print.Printer, cmd *cobra.Command, outputFormat string, bac if err != nil { return fmt.Errorf("marshal backup for PostgreSQL Flex backup: %w", err) } - cmd.Println(string(details)) + p.Outputln(string(details)) return nil case print.YAMLOutputFormat: diff --git a/internal/cmd/postgresflex/backup/describe/describe_test.go b/internal/cmd/postgresflex/backup/describe/describe_test.go index c2aab7317..e3f8dd6f1 100644 --- a/internal/cmd/postgresflex/backup/describe/describe_test.go +++ b/internal/cmd/postgresflex/backup/describe/describe_test.go @@ -3,12 +3,14 @@ package describe import ( "context" "testing" - - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" + "time" "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/postgresflex" ) @@ -235,3 +237,37 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + backup postgresflex.Backup + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{}, true}, + {"standard", args{outputFormat: "", backup: postgresflex.Backup{StartTime: utils.Ptr(time.Now().Format(time.RFC3339))}}, false}, + {"complete", args{outputFormat: "", backup: postgresflex.Backup{ + EndTime: utils.Ptr(time.Now().Format(time.RFC3339)), + Id: utils.Ptr("id"), + Labels: &[]string{"foo", "bar", "baz"}, + Name: utils.Ptr("name"), + Options: &map[string]string{"test1": "test1", "test2": "test2"}, + Size: utils.Ptr(int64(42)), + StartTime: utils.Ptr(time.Now().Format(time.RFC3339)), + }}, 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.backup); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/postgresflex/backup/list/list.go b/internal/cmd/postgresflex/backup/list/list.go index a8416f602..0b7ab5234 100644 --- a/internal/cmd/postgresflex/backup/list/list.go +++ b/internal/cmd/postgresflex/backup/list/list.go @@ -157,7 +157,7 @@ func outputResult(p *print.Printer, outputFormat string, backups []postgresflex. for i := range backups { backup := backups[i] - backupStartTime, err := time.Parse(time.RFC3339, *backup.StartTime) + backupStartTime, err := time.Parse(time.RFC3339, utils.PtrString(backup.StartTime)) if err != nil { return fmt.Errorf("parse backup start time: %w", err) } diff --git a/internal/cmd/postgresflex/backup/list/list_test.go b/internal/cmd/postgresflex/backup/list/list_test.go index 242bc9563..302aed436 100644 --- a/internal/cmd/postgresflex/backup/list/list_test.go +++ b/internal/cmd/postgresflex/backup/list/list_test.go @@ -3,13 +3,14 @@ package list import ( "context" "testing" - - "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "time" "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/postgresflex" ) @@ -205,3 +206,49 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + backups []postgresflex.Backup + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{}, false}, + {"standard", args{outputFormat: "", backups: []postgresflex.Backup{}}, false}, + {"complete", args{outputFormat: "", backups: []postgresflex.Backup{ + { + EndTime: utils.Ptr(time.Now().Format(time.RFC3339)), + Id: utils.Ptr("id"), + Labels: &[]string{"foo", "bar", "baz"}, + Name: utils.Ptr("name"), + Options: &map[string]string{"test1": "test1", "test2": "test2"}, + Size: utils.Ptr(int64(42)), + StartTime: utils.Ptr(time.Now().Format(time.RFC3339)), + }, + { + EndTime: utils.Ptr(time.Now().Format(time.RFC3339)), + Id: utils.Ptr("id"), + Labels: &[]string{"foo", "bar", "baz"}, + Name: utils.Ptr("name"), + Options: &map[string]string{"test1": "test1", "test2": "test2"}, + Size: utils.Ptr(int64(42)), + StartTime: utils.Ptr(time.Now().Format(time.RFC3339)), + }, + }, + }, 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.backups); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/postgresflex/instance/clone/clone.go b/internal/cmd/postgresflex/instance/clone/clone.go index 4ca79de4b..56dde3809 100644 --- a/internal/cmd/postgresflex/instance/clone/clone.go +++ b/internal/cmd/postgresflex/instance/clone/clone.go @@ -108,7 +108,7 @@ func NewCmd(p *print.Printer) *cobra.Command { s.Stop() } - return outputResult(p, model, instanceLabel, instanceId, resp) + return outputResult(p, model.OutputFormat, model.Async, instanceLabel, instanceId, resp) }, } configureFlags(cmd) @@ -205,8 +205,11 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient PostgreSQLFl return req, nil } -func outputResult(p *print.Printer, model *inputModel, instanceLabel, instanceId string, resp *postgresflex.CloneInstanceResponse) error { - switch model.OutputFormat { +func outputResult(p *print.Printer, outputFormat string, async bool, instanceLabel, instanceId string, resp *postgresflex.CloneInstanceResponse) error { + if resp == nil { + return fmt.Errorf("response not set") + } + switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(resp, "", " ") if err != nil { @@ -225,7 +228,7 @@ func outputResult(p *print.Printer, model *inputModel, instanceLabel, instanceId return nil default: operationState := "Cloned" - if model.Async { + if async { operationState = "Triggered cloning of" } p.Info("%s instance from instance %q. New Instance ID: %s\n", operationState, instanceLabel, instanceId) diff --git a/internal/cmd/postgresflex/instance/clone/clone_test.go b/internal/cmd/postgresflex/instance/clone/clone_test.go index 47906de21..dfb8e6e67 100644 --- a/internal/cmd/postgresflex/instance/clone/clone_test.go +++ b/internal/cmd/postgresflex/instance/clone/clone_test.go @@ -6,13 +6,12 @@ import ( "testing" "time" - "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/postgresflex" ) @@ -529,3 +528,35 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + OutputFormat string + instanceLabel string + instanceId string + async bool + resp *postgresflex.CloneInstanceResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{}, true}, + {"standard", args{ + instanceLabel: "foo", + instanceId: "bar", + resp: &postgresflex.CloneInstanceResponse{InstanceId: utils.Ptr("id")}, + }, 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.async, tt.args.instanceLabel, 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/postgresflex/instance/create/create.go b/internal/cmd/postgresflex/instance/create/create.go index 062107375..41217ffa5 100644 --- a/internal/cmd/postgresflex/instance/create/create.go +++ b/internal/cmd/postgresflex/instance/create/create.go @@ -133,7 +133,7 @@ func NewCmd(p *print.Printer) *cobra.Command { s.Stop() } - return outputResult(p, model, projectLabel, instanceId, resp) + return outputResult(p, model.OutputFormat, model.Async, projectLabel, instanceId, resp) }, } configureFlags(cmd) @@ -273,8 +273,11 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient PostgreSQLFl return req, nil } -func outputResult(p *print.Printer, model *inputModel, projectLabel, instanceId string, resp *postgresflex.CreateInstanceResponse) error { - switch model.OutputFormat { +func outputResult(p *print.Printer, outputFormat string, async bool, projectLabel, instanceId string, resp *postgresflex.CreateInstanceResponse) error { + if resp == nil { + return fmt.Errorf("no response passed") + } + switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(resp, "", " ") if err != nil { @@ -293,7 +296,7 @@ func outputResult(p *print.Printer, model *inputModel, projectLabel, instanceId return nil default: operationState := "Created" - if model.Async { + if async { operationState = "Triggered creation of" } p.Outputf("%s instance for project %q. Instance ID: %s\n", operationState, projectLabel, instanceId) diff --git a/internal/cmd/postgresflex/instance/create/create_test.go b/internal/cmd/postgresflex/instance/create/create_test.go index 8b9bb9450..401665161 100644 --- a/internal/cmd/postgresflex/instance/create/create_test.go +++ b/internal/cmd/postgresflex/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/postgresflex" ) @@ -521,3 +520,38 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + async bool + projectLabel string + instanceId string + resp *postgresflex.CreateInstanceResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{}, true}, + {"standard", args{ + outputFormat: "", + async: false, + projectLabel: "label", + instanceId: "4711", + resp: &postgresflex.CreateInstanceResponse{Id: utils.Ptr("id")}, + }, + 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.async, 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/postgresflex/instance/describe/describe.go b/internal/cmd/postgresflex/instance/describe/describe.go index c65ebfda1..7e99a129a 100644 --- a/internal/cmd/postgresflex/instance/describe/describe.go +++ b/internal/cmd/postgresflex/instance/describe/describe.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "strings" "github.com/goccy/go-yaml" "github.com/stackitcloud/stackit-cli/internal/pkg/args" @@ -102,6 +101,9 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *postgresfle } func outputResult(p *print.Printer, outputFormat string, instance *postgresflex.Instance) error { + if instance == nil { + return fmt.Errorf("no response passed") + } switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(instance, "", " ") @@ -122,11 +124,10 @@ func outputResult(p *print.Printer, outputFormat string, instance *postgresflex. default: acls := "" if instance.HasAcl() && instance.Acl.HasItems() { - aclsArray := *instance.Acl.Items - acls = strings.Join(aclsArray, ",") + acls = utils.JoinStringPtr(instance.Acl.Items, ",") } - instanceType, err := postgresflexUtils.GetInstanceType(*instance.Replicas) + instanceType, err := postgresflexUtils.GetInstanceType(utils.PtrValue(instance.Replicas)) if err != nil { // Should never happen instanceType = "" @@ -139,21 +140,27 @@ func outputResult(p *print.Printer, outputFormat string, instance *postgresflex. table.AddSeparator() table.AddRow("STATUS", cases.Title(language.English).String(utils.PtrString(instance.Status))) table.AddSeparator() - table.AddRow("STORAGE SIZE (GB)", utils.PtrString(instance.Storage.Size)) + if instance.Storage != nil { + table.AddRow("STORAGE SIZE (GB)", utils.PtrString(instance.Storage.Size)) + } table.AddSeparator() table.AddRow("VERSION", utils.PtrString(instance.Version)) table.AddSeparator() table.AddRow("ACL", acls) table.AddSeparator() - table.AddRow("FLAVOR DESCRIPTION", utils.PtrString(instance.Flavor.Description)) + if instance.Flavor != nil { + table.AddRow("FLAVOR DESCRIPTION", utils.PtrString(instance.Flavor.Description)) + } table.AddSeparator() table.AddRow("TYPE", instanceType) table.AddSeparator() table.AddRow("REPLICAS", utils.PtrString(instance.Replicas)) table.AddSeparator() - table.AddRow("CPU", utils.PtrString(instance.Flavor.Cpu)) - table.AddSeparator() - table.AddRow("RAM (GB)", utils.PtrString(instance.Flavor.Memory)) + if instance.Flavor != nil { + table.AddRow("CPU", utils.PtrString(instance.Flavor.Cpu)) + table.AddSeparator() + table.AddRow("RAM (GB)", utils.PtrString(instance.Flavor.Memory)) + } table.AddSeparator() table.AddRow("BACKUP SCHEDULE (UTC)", utils.PtrString(instance.BackupSchedule)) table.AddSeparator() diff --git a/internal/cmd/postgresflex/instance/describe/describe_test.go b/internal/cmd/postgresflex/instance/describe/describe_test.go index b71920a5b..825e481f1 100644 --- a/internal/cmd/postgresflex/instance/describe/describe_test.go +++ b/internal/cmd/postgresflex/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/postgresflex" ) @@ -216,3 +215,56 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + instance *postgresflex.Instance + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{}, true}, + {"standard", args{ + outputFormat: "", + instance: &postgresflex.Instance{}, + }, false}, + {"complete", args{ + outputFormat: "", + instance: &postgresflex.Instance{ + Acl: &postgresflex.ACL{ + Items: &[]string{}, + }, + BackupSchedule: new(string), + Flavor: &postgresflex.Flavor{ + Cpu: new(int64), + Description: new(string), + Id: new(string), + Memory: new(int64), + }, + Id: new(string), + Name: new(string), + Options: &map[string]string{}, + Replicas: new(int64), + Status: new(string), + Storage: &postgresflex.Storage{ + Class: new(string), + Size: new(int64), + }, + Version: new(string), + }, + }, 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/postgresflex/instance/list/list_test.go b/internal/cmd/postgresflex/instance/list/list_test.go index 0060c7645..11d835caf 100644 --- a/internal/cmd/postgresflex/instance/list/list_test.go +++ b/internal/cmd/postgresflex/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/postgresflex" ) @@ -186,3 +185,45 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + instances []postgresflex.InstanceListInstance + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{}, false}, + {"standard", args{"", []postgresflex.InstanceListInstance{}}, false}, + {"complete", args{"", []postgresflex.InstanceListInstance{ + { + Id: new(string), + Name: new(string), + Status: new(string), + }, + { + Id: new(string), + Name: new(string), + Status: new(string), + }, + { + Id: new(string), + Name: new(string), + Status: new(string), + }, + }}, 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/postgresflex/instance/update/update.go b/internal/cmd/postgresflex/instance/update/update.go index c5f1857f6..c52b2efc3 100644 --- a/internal/cmd/postgresflex/instance/update/update.go +++ b/internal/cmd/postgresflex/instance/update/update.go @@ -118,7 +118,7 @@ func NewCmd(p *print.Printer) *cobra.Command { s.Stop() } - return outputResult(p, model, instanceLabel, resp) + return outputResult(p, model.OutputFormat, model.Async, instanceLabel, resp) }, } configureFlags(cmd) @@ -307,8 +307,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient PostgreSQLFl return req, nil } -func outputResult(p *print.Printer, model *inputModel, instanceLabel string, resp *postgresflex.PartialUpdateInstanceResponse) error { - switch model.OutputFormat { +func outputResult(p *print.Printer, outputFormat string, async bool, instanceLabel string, resp *postgresflex.PartialUpdateInstanceResponse) error { + if resp == nil { + return fmt.Errorf("no response passed") + } + + switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(resp, "", " ") if err != nil { @@ -327,7 +331,7 @@ func outputResult(p *print.Printer, model *inputModel, instanceLabel string, res return nil default: operationState := "Updated" - if model.Async { + if async { operationState = "Triggered update of" } p.Info("%s instance %q\n", operationState, instanceLabel) diff --git a/internal/cmd/postgresflex/instance/update/update_test.go b/internal/cmd/postgresflex/instance/update/update_test.go index 5ac0a472f..edc536024 100644 --- a/internal/cmd/postgresflex/instance/update/update_test.go +++ b/internal/cmd/postgresflex/instance/update/update_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/postgresflex" ) @@ -590,3 +589,41 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + instanceLabel string + resp *postgresflex.PartialUpdateInstanceResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty model", args{}, true}, + {"empty response", args{outputFormat: ""}, true}, + {"standard", args{ + outputFormat: "", + instanceLabel: "test", + resp: &postgresflex.PartialUpdateInstanceResponse{}, + }, false}, + {"complet", args{ + outputFormat: "", + instanceLabel: "test", + resp: &postgresflex.PartialUpdateInstanceResponse{ + Item: &postgresflex.Instance{}, + }, + }, 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, true, 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/postgresflex/options/options.go b/internal/cmd/postgresflex/options/options.go index d21067aa1..a8ac9a614 100644 --- a/internal/cmd/postgresflex/options/options.go +++ b/internal/cmd/postgresflex/options/options.go @@ -166,14 +166,17 @@ func buildAndExecuteRequest(ctx context.Context, p *print.Printer, model *inputM } } - return outputResult(p, model, flavors, versions, storages) + return outputResult(p, *model, flavors, versions, storages) } -func outputResult(p *print.Printer, model *inputModel, flavors *postgresflex.ListFlavorsResponse, versions *postgresflex.ListVersionsResponse, storages *postgresflex.ListStoragesResponse) error { +func outputResult(p *print.Printer, model inputModel, flavors *postgresflex.ListFlavorsResponse, versions *postgresflex.ListVersionsResponse, storages *postgresflex.ListStoragesResponse) error { options := &options{} if flavors != nil { options.Flavors = flavors.Flavors } + if model.GlobalFlagModel == nil { + return fmt.Errorf("no global model defined") + } if versions != nil { options.Versions = versions.Versions } @@ -205,7 +208,7 @@ func outputResult(p *print.Printer, model *inputModel, flavors *postgresflex.Lis } } -func outputResultAsTable(p *print.Printer, model *inputModel, options *options) error { +func outputResultAsTable(p *print.Printer, model inputModel, options *options) error { content := []tables.Table{} if model.Flavors && len(*options.Flavors) != 0 { content = append(content, buildFlavorsTable(*options.Flavors)) diff --git a/internal/cmd/postgresflex/options/options_test.go b/internal/cmd/postgresflex/options/options_test.go index 1a4866a3b..5eebac304 100644 --- a/internal/cmd/postgresflex/options/options_test.go +++ b/internal/cmd/postgresflex/options/options_test.go @@ -5,11 +5,10 @@ import ( "fmt" "testing" + "github.com/google/go-cmp/cmp" "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/stackitcloud/stackit-sdk-go/services/postgresflex" ) @@ -322,3 +321,51 @@ func TestBuildAndExecuteRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + model inputModel + flavors *postgresflex.ListFlavorsResponse + versions *postgresflex.ListVersionsResponse + storages *postgresflex.ListStoragesResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{model: inputModel{GlobalFlagModel: &globalflags.GlobalFlagModel{}}}, false}, + {"standard", args{ + model: inputModel{GlobalFlagModel: &globalflags.GlobalFlagModel{}}, + flavors: &postgresflex.ListFlavorsResponse{}, + versions: &postgresflex.ListVersionsResponse{}, + storages: &postgresflex.ListStoragesResponse{}, + }, false}, + { + "complete", + args{ + model: inputModel{GlobalFlagModel: &globalflags.GlobalFlagModel{}, Flavors: false, Versions: false, Storages: false, FlavorId: new(string)}, + flavors: &postgresflex.ListFlavorsResponse{ + Flavors: &[]postgresflex.Flavor{}, + }, + versions: &postgresflex.ListVersionsResponse{ + Versions: &[]string{}, + }, + storages: &postgresflex.ListStoragesResponse{ + StorageClasses: &[]string{}, + StorageRange: &postgresflex.StorageRange{}, + }, + }, + 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.model, tt.args.flavors, tt.args.versions, tt.args.storages); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/postgresflex/user/create/create.go b/internal/cmd/postgresflex/user/create/create.go index 4638da73d..44a518d79 100644 --- a/internal/cmd/postgresflex/user/create/create.go +++ b/internal/cmd/postgresflex/user/create/create.go @@ -90,7 +90,7 @@ func NewCmd(p *print.Printer) *cobra.Command { return fmt.Errorf("create PostgreSQL Flex user: %w", err) } - return outputResult(p, model, instanceLabel, resp) + return outputResult(p, model.OutputFormat, instanceLabel, resp) }, } @@ -143,8 +143,11 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *postgresfle return req } -func outputResult(p *print.Printer, model *inputModel, instanceLabel string, resp *postgresflex.CreateUserResponse) error { - switch model.OutputFormat { +func outputResult(p *print.Printer, outputFormat, instanceLabel string, resp *postgresflex.CreateUserResponse) error { + if resp == nil { + return fmt.Errorf("no response passed") + } + switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(resp, "", " ") if err != nil { @@ -162,14 +165,15 @@ func outputResult(p *print.Printer, model *inputModel, instanceLabel string, res return nil default: - user := resp.Item - p.Outputf("Created user for instance %q. User ID: %s\n\n", instanceLabel, utils.PtrString(user.Id)) - p.Outputf("Username: %s\n", utils.PtrString(user.Username)) - p.Outputf("Password: %s\n", utils.PtrString(user.Password)) - p.Outputf("Roles: %v\n", utils.PtrString(user.Roles)) - p.Outputf("Host: %s\n", utils.PtrString(user.Host)) - p.Outputf("Port: %s\n", utils.PtrString(user.Port)) - p.Outputf("URI: %s\n", utils.PtrString(user.Uri)) + if user := resp.Item; user != nil { + p.Outputf("Created user for instance %q. User ID: %s\n\n", instanceLabel, utils.PtrString(user.Id)) + p.Outputf("Username: %s\n", utils.PtrString(user.Username)) + p.Outputf("Password: %s\n", utils.PtrString(user.Password)) + p.Outputf("Roles: %v\n", utils.PtrString(user.Roles)) + p.Outputf("Host: %s\n", utils.PtrString(user.Host)) + p.Outputf("Port: %s\n", utils.PtrString(user.Port)) + p.Outputf("URI: %s\n", utils.PtrString(user.Uri)) + } return nil } diff --git a/internal/cmd/postgresflex/user/create/create_test.go b/internal/cmd/postgresflex/user/create/create_test.go index d90533633..ab5a43277 100644 --- a/internal/cmd/postgresflex/user/create/create_test.go +++ b/internal/cmd/postgresflex/user/create/create_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/postgresflex" ) @@ -230,3 +229,41 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + instanceLabel string + resp *postgresflex.CreateUserResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{}, true}, + {"standard", args{resp: &postgresflex.CreateUserResponse{}}, false}, + {"complete", args{resp: &postgresflex.CreateUserResponse{ + Item: &postgresflex.User{ + Database: new(string), + Host: new(string), + Id: new(string), + Password: new(string), + Port: new(int64), + Roles: &[]string{}, + Uri: new(string), + Username: new(string), + }, + }}, 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.instanceLabel, tt.args.resp); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/postgresflex/user/describe/describe_test.go b/internal/cmd/postgresflex/user/describe/describe_test.go index 967c5c640..c3dadb008 100644 --- a/internal/cmd/postgresflex/user/describe/describe_test.go +++ b/internal/cmd/postgresflex/user/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/postgresflex" ) @@ -237,3 +236,35 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + user postgresflex.UserResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"basic", args{}, false}, + {"standard", args{user: postgresflex.UserResponse{}}, false}, + {"complete", args{user: postgresflex.UserResponse{ + Host: new(string), + Id: new(string), + Port: new(int64), + Roles: &[]string{}, + Username: new(string), + }}, 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.user); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/postgresflex/user/list/list_test.go b/internal/cmd/postgresflex/user/list/list_test.go index 671b7e383..fb042f6c9 100644 --- a/internal/cmd/postgresflex/user/list/list_test.go +++ b/internal/cmd/postgresflex/user/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/postgresflex" ) @@ -203,3 +202,32 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + users []postgresflex.ListUsersResponseItem + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{}, false}, + {"standard", args{users: []postgresflex.ListUsersResponseItem{{}}}, false}, + {"complete", args{users: []postgresflex.ListUsersResponseItem{{ + Id: new(string), + Username: new(string), + }}}, 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.users); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/cmd/postgresflex/user/reset-password/reset_password.go b/internal/cmd/postgresflex/user/reset-password/reset_password.go index 60abaf04a..14163d879 100644 --- a/internal/cmd/postgresflex/user/reset-password/reset_password.go +++ b/internal/cmd/postgresflex/user/reset-password/reset_password.go @@ -86,7 +86,7 @@ func NewCmd(p *print.Printer) *cobra.Command { return fmt.Errorf("reset PostgreSQL Flex user password: %w", err) } - return outputResult(p, model, userLabel, instanceLabel, user) + return outputResult(p, model.OutputFormat, userLabel, instanceLabel, user) }, } @@ -132,8 +132,11 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *postgresfle return req } -func outputResult(p *print.Printer, model *inputModel, userLabel, instanceLabel string, user *postgresflex.ResetUserResponse) error { - switch model.OutputFormat { +func outputResult(p *print.Printer, outputFormat, userLabel, instanceLabel string, user *postgresflex.ResetUserResponse) error { + if user == nil { + return fmt.Errorf("no response passed") + } + switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(user, "", " ") if err != nil { @@ -152,9 +155,11 @@ func outputResult(p *print.Printer, model *inputModel, userLabel, instanceLabel return nil default: p.Outputf("Reset password for user %q of instance %q\n\n", userLabel, instanceLabel) - p.Outputf("Username: %s\n", utils.PtrString(user.Item.Username)) - p.Outputf("New password: %s\n", utils.PtrString(user.Item.Password)) - p.Outputf("New URI: %s\n", utils.PtrString(user.Item.Uri)) + if item := user.Item; item != nil { + p.Outputf("Username: %s\n", utils.PtrString(item.Username)) + p.Outputf("New password: %s\n", utils.PtrString(item.Password)) + p.Outputf("New URI: %s\n", utils.PtrString(item.Uri)) + } return nil } } diff --git a/internal/cmd/postgresflex/user/reset-password/reset_password_test.go b/internal/cmd/postgresflex/user/reset-password/reset_password_test.go index f147797a0..d984f0271 100644 --- a/internal/cmd/postgresflex/user/reset-password/reset_password_test.go +++ b/internal/cmd/postgresflex/user/reset-password/reset_password_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/postgresflex" ) @@ -237,3 +236,36 @@ func TestBuildRequest(t *testing.T) { }) } } + +func Test_outputResult(t *testing.T) { + type args struct { + outputFormat string + userLabel string + instanceLabel string + user *postgresflex.ResetUserResponse + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"empty", args{}, true}, + {"standard", args{user: &postgresflex.ResetUserResponse{}}, false}, + {"complete", args{ + userLabel: "userLabel", + instanceLabel: "instanceLabel", + user: &postgresflex.ResetUserResponse{ + Item: &postgresflex.User{}, + }}, 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.userLabel, tt.args.instanceLabel, tt.args.user); (err != nil) != tt.wantErr { + t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/pkg/utils/utils.go b/internal/pkg/utils/utils.go index e8fea5884..a8b2a31b3 100644 --- a/internal/pkg/utils/utils.go +++ b/internal/pkg/utils/utils.go @@ -27,6 +27,15 @@ func PtrString[T any](t *T) string { return "" } +// PtrValue returns the dereferenced value if the pointer is not nil. Otherwise +// the types zero element is returned +func PtrValue[T any](t *T) (r T) { + if t != nil { + return *t + } + return r +} + // Int64Ptr returns a pointer to an int64 // Needed because the Ptr function only returns pointer to int func Int64Ptr(i int64) *int64 {