diff --git a/CHANGELOG.md b/CHANGELOG.md index 60d197428..0b8b34f29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -316,6 +316,8 @@ - **Dependencies:** Bump STACKIT SDK core module from `v0.24.1` to `v0.25.0` - [v0.28.2](services/redis/CHANGELOG.md#v0282) - **Dependencies:** Bump STACKIT SDK core module from `v0.25.0` to `v0.26.0` + - [v0.29.0](services/redis/CHANGELOG.md#v0290) + - `v1api`: **Improvement**: Use new `WaiterHandler` struct in the Redis WaitHandler - `resourcemanager`: - [v0.21.2](services/resourcemanager/CHANGELOG.md#v0212) - **Dependencies:** Bump STACKIT SDK core module from `v0.24.0` to `v0.24.1` diff --git a/services/redis/CHANGELOG.md b/services/redis/CHANGELOG.md index cf6d467b0..8e2069beb 100644 --- a/services/redis/CHANGELOG.md +++ b/services/redis/CHANGELOG.md @@ -1,3 +1,6 @@ +## v0.29.0 +- `v1api`: **Improvement**: Use new `WaiterHandler` struct in the Redis WaitHandler + ## v0.28.2 - **Dependencies:** Bump STACKIT SDK core module from `v0.25.0` to `v0.26.0` diff --git a/services/redis/VERSION b/services/redis/VERSION index f53b7bda1..5bc296535 100644 --- a/services/redis/VERSION +++ b/services/redis/VERSION @@ -1 +1 @@ -v0.28.2 \ No newline at end of file +v0.29.0 \ No newline at end of file diff --git a/services/redis/v1api/wait/wait.go b/services/redis/v1api/wait/wait.go index ae0e8c238..962e31b6e 100644 --- a/services/redis/v1api/wait/wait.go +++ b/services/redis/v1api/wait/wait.go @@ -2,6 +2,7 @@ package wait import ( "context" + "errors" "fmt" "net/http" "strings" @@ -25,48 +26,35 @@ const ( INSTANCELASTOPERATIONTYPE_DELETE = "delete" ) -// CreateInstanceWaitHandler will wait for instance creation -func CreateInstanceWaitHandler(ctx context.Context, a redis.DefaultAPI, projectId, instanceId string) *wait.AsyncActionHandler[redis.Instance] { - handler := wait.New(func() (waitFinished bool, response *redis.Instance, err error) { - s, err := a.GetInstance(ctx, projectId, instanceId).Execute() - if err != nil { - return false, nil, err - } - if s.Status == nil { - return false, nil, fmt.Errorf("create failed for instance with id %s. The response is not valid: the status is missing", instanceId) - } - switch *s.Status { - case INSTANCESTATUS_ACTIVE: - return true, s, nil - case INSTANCESTATUS_FAILED: - return true, s, fmt.Errorf("create failed for instance with id %s: %s", instanceId, s.LastOperation.Description) - } - return false, nil, nil - }) +func createOrUpdateInstanceWaitHandler(ctx context.Context, client redis.DefaultAPI, projectId, instanceId string) *wait.AsyncActionHandler[redis.Instance] { + waitConfig := wait.WaiterHelper[redis.Instance, string]{ + FetchInstance: client.GetInstance(ctx, projectId, instanceId).Execute, + GetState: func(response *redis.Instance) (string, error) { + if response == nil { + return "", errors.New("empty response") + } + if response.Status == nil { + return "", errors.New("status is missing in response") + } + return *response.Status, nil + }, + ActiveState: []string{INSTANCESTATUS_ACTIVE}, + ErrorState: []string{INSTANCESTATUS_FAILED}, + } + + handler := wait.New(waitConfig.Wait()) handler.SetTimeout(45 * time.Minute) return handler } +// CreateInstanceWaitHandler will wait for instance creation +func CreateInstanceWaitHandler(ctx context.Context, client redis.DefaultAPI, projectId, instanceId string) *wait.AsyncActionHandler[redis.Instance] { + return createOrUpdateInstanceWaitHandler(ctx, client, projectId, instanceId) +} + // PartialUpdateInstanceWaitHandler will wait for instance update -func PartialUpdateInstanceWaitHandler(ctx context.Context, a redis.DefaultAPI, projectId, instanceId string) *wait.AsyncActionHandler[redis.Instance] { - handler := wait.New(func() (waitFinished bool, response *redis.Instance, err error) { - s, err := a.GetInstance(ctx, projectId, instanceId).Execute() - if err != nil { - return false, nil, err - } - if s.Status == nil { - return false, nil, fmt.Errorf("update failed for instance with id %s. The response is not valid: the instance id or the status are missing", instanceId) - } - switch *s.Status { - case INSTANCESTATUS_ACTIVE: - return true, s, nil - case INSTANCESTATUS_FAILED: - return true, s, fmt.Errorf("update failed for instance with id %s: %s", instanceId, s.LastOperation.Description) - } - return false, nil, nil - }) - handler.SetTimeout(45 * time.Minute) - return handler +func PartialUpdateInstanceWaitHandler(ctx context.Context, client redis.DefaultAPI, projectId, instanceId string) *wait.AsyncActionHandler[redis.Instance] { + return createOrUpdateInstanceWaitHandler(ctx, client, projectId, instanceId) } // DeleteInstanceWaitHandler will wait for instance deletion diff --git a/services/redis/v1api/wait/wait_test.go b/services/redis/v1api/wait/wait_test.go index e71d036b1..1c51d15c1 100644 --- a/services/redis/v1api/wait/wait_test.go +++ b/services/redis/v1api/wait/wait_test.go @@ -2,6 +2,7 @@ package wait import ( "context" + "fmt" "testing" "testing/synctest" "time" @@ -10,6 +11,7 @@ import ( "github.com/stackitcloud/stackit-sdk-go/core/oapierror" "github.com/stackitcloud/stackit-sdk-go/core/utils" + "github.com/stackitcloud/stackit-sdk-go/core/wait" redis "github.com/stackitcloud/stackit-sdk-go/services/redis/v1api" ) @@ -76,7 +78,7 @@ func newAPIMock(settings *mockSettings) redis.DefaultAPI { } } -func TestCreateInstanceWaitHandler(t *testing.T) { +func TestCreateOrUpdateInstanceWaitHandler(t *testing.T) { tests := []struct { desc string getFails bool @@ -85,90 +87,26 @@ func TestCreateInstanceWaitHandler(t *testing.T) { wantResp bool }{ { - desc: "create_succeeded", + desc: "create_or_update_succeeded", getFails: false, resourceState: utils.Ptr(INSTANCESTATUS_ACTIVE), wantErr: false, wantResp: true, }, { - desc: "create_failed", + desc: "create_or_update_failed", getFails: false, resourceState: utils.Ptr(INSTANCESTATUS_FAILED), wantErr: true, wantResp: true, }, { - desc: "get_fails", - getFails: true, - wantErr: true, - wantResp: false, - }, - { - desc: "timeout", + desc: "wrong state in response", getFails: false, - resourceState: utils.Ptr("ANOTHER STATE"), + resourceState: utils.Ptr("wrong state"), wantErr: true, wantResp: false, }, - } - for _, tt := range tests { - t.Run(tt.desc, func(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - instanceId := "foo-bar" - - apiClient := newAPIMock(&mockSettings{ - instanceGetFails: tt.getFails, - instanceResourceId: instanceId, - instanceResourceState: tt.resourceState, - }) - - var wantRes *redis.Instance - if tt.wantResp { - wantRes = &redis.Instance{ - InstanceId: &instanceId, - Status: tt.resourceState, - } - } - - handler := CreateInstanceWaitHandler(context.Background(), apiClient, "pid", instanceId) - - gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) - - if (err != nil) != tt.wantErr { - t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) - } - diff := cmp.Diff(gotRes, wantRes) - if diff != "" { - t.Fatalf("handler gotRes = %+v\n want %+v\n diff = %s", gotRes, wantRes, diff) - } - }) - }) - } -} - -func TestUpdateInstanceWaitHandler(t *testing.T) { - tests := []struct { - desc string - getFails bool - resourceState *string - wantErr bool - wantResp bool - }{ - { - desc: "update_succeeded", - getFails: false, - resourceState: utils.Ptr(INSTANCESTATUS_ACTIVE), - wantErr: false, - wantResp: true, - }, - { - desc: "update_failed", - getFails: false, - resourceState: utils.Ptr(INSTANCESTATUS_FAILED), - wantErr: true, - wantResp: true, - }, { desc: "get_fails", getFails: true, @@ -183,37 +121,46 @@ func TestUpdateInstanceWaitHandler(t *testing.T) { wantResp: false, }, } - for _, tt := range tests { - t.Run(tt.desc, func(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - instanceId := "foo-bar" - apiClient := newAPIMock(&mockSettings{ - instanceGetFails: tt.getFails, - instanceResourceId: instanceId, - instanceResourceState: tt.resourceState, - }) + handlers := map[string]func(context.Context, redis.DefaultAPI, string, string) *wait.AsyncActionHandler[redis.Instance]{ + "common logic": createOrUpdateInstanceWaitHandler, + "create": CreateInstanceWaitHandler, + "update": PartialUpdateInstanceWaitHandler, + } - var wantRes *redis.Instance - if tt.wantResp { - wantRes = &redis.Instance{ - InstanceId: &instanceId, - Status: tt.resourceState, + for handlerDesc, handlerFn := range handlers { + for _, tt := range tests { + t.Run(fmt.Sprintf("%s - %s", handlerDesc, tt.desc), func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + instanceId := "foo-bar" + + apiClient := newAPIMock(&mockSettings{ + instanceGetFails: tt.getFails, + instanceResourceId: instanceId, + instanceResourceState: tt.resourceState, + }) + + var wantRes *redis.Instance + if tt.wantResp { + wantRes = &redis.Instance{ + InstanceId: &instanceId, + Status: tt.resourceState, + } } - } - - handler := PartialUpdateInstanceWaitHandler(context.Background(), apiClient, "", instanceId) - gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + handler := handlerFn(context.Background(), apiClient, "pid", instanceId) + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) - if (err != nil) != tt.wantErr { - t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) - } - if !cmp.Equal(gotRes, wantRes) { - t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) - } + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + diff := cmp.Diff(gotRes, wantRes) + if diff != "" { + t.Fatalf("handler gotRes = %+v\n want %+v\n diff = %s", gotRes, wantRes, diff) + } + }) }) - }) + } } }