Skip to content

Commit 37793bc

Browse files
authored
feat(sqlserverflex): refactor wait handler to use helper struct (#7448)
relates to STACKITSDK-394
1 parent c01fe6f commit 37793bc

5 files changed

Lines changed: 98 additions & 181 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,11 @@
548548
- [v1.11.0](services/sqlserverflex/CHANGELOG.md#v1110)
549549
- `v3beta1api`: **Feature:** Added `labels` to `CreateInstanceRequestPayload`, `GetInstanceReponse`, `UpdateInstancePartiallyRequestPayload`, `UpdateInstanceRequestPayload`
550550
- [v1.12.0](services/sqlserverflex/CHANGELOG.md#v1120)
551-
- **Feature:** Introduce enums for various attributes
551+
- **Feature:** Introduce enums for various attributes
552+
- [v1.13.0](services/sqlserverflex/CHANGELOG.md#v1130)
553+
- `v2api`:
554+
- **Improvement**: Use new `WaiterHelper` struct in the SQLServer Flex WaitHandler
555+
- **Breaking change:** Change return type of `wait.DeleteInstanceWaitHandler()` to `*wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse]`
552556
- `stackitmarketplace`:
553557
- [v1.17.5](services/stackitmarketplace/CHANGELOG.md#v1175)
554558
- **Dependencies:** Bump STACKIT SDK core module from `v0.24.0` to `v0.24.1`

services/sqlserverflex/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## v1.13.0
2+
- `v2api`:
3+
- **Improvement**: Use new `WaiterHelper` struct in the SQLServer Flex WaitHandler
4+
- **Breaking change:** Change return type of `wait.DeleteInstanceWaitHandler()` to `*wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse]`
5+
16
## v1.12.0
27
- **Feature:** Introduce enums for various attributes
38

services/sqlserverflex/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v1.12.0
1+
v1.13.0

services/sqlserverflex/v2api/wait/wait.go

Lines changed: 43 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@ package wait
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"net/http"
8-
"strings"
97
"time"
108

11-
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
129
"github.com/stackitcloud/stackit-sdk-go/core/wait"
1310
sqlserverflex "github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex/v2api"
1411
)
@@ -21,76 +18,58 @@ const (
2118
InstanceStateFailed = "Failed"
2219
)
2320

24-
// CreateInstanceWaitHandler will wait for instance creation
25-
func CreateInstanceWaitHandler(ctx context.Context, a sqlserverflex.DefaultAPI, projectId, instanceId, region string) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] {
26-
handler := wait.New(func() (waitFinished bool, response *sqlserverflex.GetInstanceResponse, err error) {
27-
s, err := a.GetInstance(ctx, projectId, instanceId, region).Execute()
28-
if err != nil {
29-
return false, nil, err
30-
}
31-
if s == nil || s.Item == nil || s.Item.Id == nil || *s.Item.Id != instanceId || s.Item.Status == nil {
32-
return false, nil, nil
33-
}
34-
switch strings.ToLower(*s.Item.Status) {
35-
case strings.ToLower(InstanceStateSuccess):
36-
return true, s, nil
37-
case strings.ToLower(InstanceStateUnknown), strings.ToLower(InstanceStateFailed):
38-
return true, s, fmt.Errorf("create failed for instance with id %s", instanceId)
39-
default:
40-
return false, s, nil
41-
}
42-
})
43-
handler.SetTimeout(45 * time.Minute)
21+
func createOrUpdateInstanceWaitHandler(ctx context.Context, client sqlserverflex.DefaultAPI, projectId, instanceId, region string) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] {
22+
waitConfig := wait.WaiterHelper[sqlserverflex.GetInstanceResponse, string]{
23+
FetchInstance: client.GetInstance(ctx, projectId, instanceId, region).Execute,
24+
GetState: func(response *sqlserverflex.GetInstanceResponse) (string, error) {
25+
if response == nil {
26+
return "", errors.New("empty response")
27+
}
28+
if response.Item == nil {
29+
return "", errors.New("empty instance")
30+
}
31+
if response.Item.Status == nil {
32+
return "", errors.New("status is missing")
33+
}
34+
return *response.Item.Status, nil
35+
},
36+
ActiveState: []string{InstanceStateSuccess},
37+
ErrorState: []string{InstanceStateUnknown, InstanceStateFailed, InstanceStateEmpty},
38+
}
39+
40+
handler := wait.New(waitConfig.Wait())
4441
handler.SetSleepBeforeWait(5 * time.Second)
42+
handler.SetTimeout(45 * time.Minute)
4543
return handler
4644
}
4745

48-
// UpdateInstanceWaitHandler will wait for instance update
49-
func UpdateInstanceWaitHandler(ctx context.Context, a sqlserverflex.DefaultAPI, projectId, instanceId, region string) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] {
50-
handler := wait.New(func() (waitFinished bool, response *sqlserverflex.GetInstanceResponse, err error) {
51-
s, err := a.GetInstance(ctx, projectId, instanceId, region).Execute()
52-
if err != nil {
53-
return false, nil, err
54-
}
55-
if s == nil || s.Item == nil || s.Item.Id == nil || *s.Item.Id != instanceId || s.Item.Status == nil {
56-
return false, nil, nil
57-
}
58-
switch strings.ToLower(*s.Item.Status) {
59-
case strings.ToLower(InstanceStateSuccess):
60-
return true, s, nil
61-
case strings.ToLower(InstanceStateUnknown), strings.ToLower(InstanceStateFailed):
62-
return true, s, fmt.Errorf("update failed for instance with id %s", instanceId)
63-
default:
64-
return false, s, nil
65-
}
66-
})
67-
handler.SetSleepBeforeWait(2 * time.Second)
68-
handler.SetTimeout(45 * time.Minute)
69-
return handler
46+
// CreateInstanceWaitHandler will wait for instance creation
47+
func CreateInstanceWaitHandler(ctx context.Context, client sqlserverflex.DefaultAPI, projectId, instanceId, region string) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] {
48+
return createOrUpdateInstanceWaitHandler(ctx, client, projectId, instanceId, region)
7049
}
7150

72-
// PartialUpdateInstanceWaitHandler will wait for instance update
73-
func PartialUpdateInstanceWaitHandler(ctx context.Context, a sqlserverflex.DefaultAPI, projectId, instanceId, region string) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] {
74-
return UpdateInstanceWaitHandler(ctx, a, projectId, instanceId, region)
51+
// UpdateInstanceWaitHandler will wait for instance update
52+
func UpdateInstanceWaitHandler(ctx context.Context, client sqlserverflex.DefaultAPI, projectId, instanceId, region string) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] {
53+
return createOrUpdateInstanceWaitHandler(ctx, client, projectId, instanceId, region)
7554
}
7655

7756
// DeleteInstanceWaitHandler will wait for instance deletion
78-
func DeleteInstanceWaitHandler(ctx context.Context, a sqlserverflex.DefaultAPI, projectId, instanceId, region string) *wait.AsyncActionHandler[struct{}] {
79-
handler := wait.New(func() (waitFinished bool, response *struct{}, err error) {
80-
_, err = a.GetInstance(ctx, projectId, instanceId, region).Execute()
81-
if err == nil {
82-
return false, nil, nil
83-
}
84-
var oapiErr *oapierror.GenericOpenAPIError
85-
ok := errors.As(err, &oapiErr)
86-
if !ok {
87-
return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError")
88-
}
89-
if oapiErr.StatusCode != http.StatusNotFound {
90-
return false, nil, err
91-
}
92-
return true, nil, nil
93-
})
57+
func DeleteInstanceWaitHandler(ctx context.Context, client sqlserverflex.DefaultAPI, projectId, instanceId, region string) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] {
58+
waitConfig := wait.WaiterHelper[sqlserverflex.GetInstanceResponse, string]{
59+
FetchInstance: client.GetInstance(ctx, projectId, instanceId, region).Execute,
60+
GetState: func(response *sqlserverflex.GetInstanceResponse) (string, error) {
61+
if response == nil {
62+
return "", errors.New("empty response")
63+
}
64+
if response.Item.Status == nil {
65+
return "", errors.New("status is missing in response")
66+
}
67+
return *response.Item.Status, nil
68+
},
69+
ErrorState: []string{InstanceStateFailed},
70+
DeleteHttpErrorStatusCodes: []int{http.StatusNotFound},
71+
}
72+
handler := wait.New(waitConfig.Wait())
9473
handler.SetTimeout(15 * time.Minute)
9574
return handler
9675
}

services/sqlserverflex/v2api/wait/wait_test.go

Lines changed: 44 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package wait
22

33
import (
44
"context"
5+
"fmt"
56
"testing"
67
"testing/synctest"
78
"time"
@@ -10,6 +11,7 @@ import (
1011

1112
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
1213
"github.com/stackitcloud/stackit-sdk-go/core/utils"
14+
"github.com/stackitcloud/stackit-sdk-go/core/wait"
1315
sqlserverflex "github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex/v2api"
1416
)
1517

@@ -46,88 +48,7 @@ func newAPIMock(settings mockSettings) sqlserverflex.DefaultAPI {
4648
}
4749
}
4850

49-
func TestCreateInstanceWaitHandler(t *testing.T) {
50-
tests := []struct {
51-
desc string
52-
instanceGetFails bool
53-
instanceState string
54-
usersGetErrorStatus int
55-
wantErr bool
56-
wantResp bool
57-
}{
58-
{
59-
desc: "create_succeeded",
60-
instanceGetFails: false,
61-
instanceState: InstanceStateSuccess,
62-
wantErr: false,
63-
wantResp: true,
64-
},
65-
{
66-
desc: "create_failed",
67-
instanceGetFails: false,
68-
instanceState: InstanceStateFailed,
69-
wantErr: true,
70-
wantResp: true,
71-
},
72-
{
73-
desc: "create_failed_2",
74-
instanceGetFails: false,
75-
instanceState: InstanceStateEmpty,
76-
wantErr: true,
77-
wantResp: true,
78-
},
79-
{
80-
desc: "instance_get_fails",
81-
instanceGetFails: true,
82-
wantErr: true,
83-
wantResp: false,
84-
},
85-
{
86-
desc: "timeout",
87-
instanceGetFails: false,
88-
instanceState: InstanceStateProcessing,
89-
wantErr: true,
90-
wantResp: true,
91-
},
92-
}
93-
for _, tt := range tests {
94-
t.Run(tt.desc, func(t *testing.T) {
95-
synctest.Test(t, func(t *testing.T) {
96-
instanceId := "foo-bar"
97-
instanceState := tt.instanceState
98-
99-
apiClient := newAPIMock(mockSettings{
100-
instanceId: &instanceId,
101-
instanceState: &instanceState,
102-
instanceGetFails: tt.instanceGetFails,
103-
})
104-
105-
var wantRes *sqlserverflex.GetInstanceResponse
106-
if tt.wantResp {
107-
wantRes = &sqlserverflex.GetInstanceResponse{
108-
Item: &sqlserverflex.Instance{
109-
Id: &instanceId,
110-
Status: utils.Ptr(tt.instanceState),
111-
},
112-
}
113-
}
114-
115-
handler := CreateInstanceWaitHandler(context.Background(), apiClient, "", instanceId, "")
116-
117-
gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background())
118-
119-
if (err != nil) != tt.wantErr {
120-
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
121-
}
122-
if !cmp.Equal(gotRes, wantRes) {
123-
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
124-
}
125-
})
126-
})
127-
}
128-
}
129-
130-
func TestUpdateInstanceWaitHandler(t *testing.T) {
51+
func TestCreateOrUpdateInstanceWaitHandler(t *testing.T) {
13152
tests := []struct {
13253
desc string
13354
instanceGetFails bool
@@ -136,28 +57,28 @@ func TestUpdateInstanceWaitHandler(t *testing.T) {
13657
wantResp bool
13758
}{
13859
{
139-
desc: "update_succeeded",
60+
desc: "create_or_update_succeeded",
14061
instanceGetFails: false,
14162
instanceState: InstanceStateSuccess,
14263
wantErr: false,
14364
wantResp: true,
14465
},
14566
{
146-
desc: "update_failed",
67+
desc: "create_or_update_failed",
14768
instanceGetFails: false,
14869
instanceState: InstanceStateFailed,
14970
wantErr: true,
15071
wantResp: true,
15172
},
15273
{
153-
desc: "update_failed_2",
74+
desc: "create_or_update_failed_2",
15475
instanceGetFails: false,
15576
instanceState: InstanceStateEmpty,
15677
wantErr: true,
15778
wantResp: true,
15879
},
15980
{
160-
desc: "get_fails",
81+
desc: "instance_get_fails",
16182
instanceGetFails: true,
16283
wantErr: true,
16384
wantResp: false,
@@ -167,43 +88,51 @@ func TestUpdateInstanceWaitHandler(t *testing.T) {
16788
instanceGetFails: false,
16889
instanceState: InstanceStateProcessing,
16990
wantErr: true,
170-
wantResp: true,
91+
wantResp: false,
17192
},
17293
}
173-
for _, tt := range tests {
174-
t.Run(tt.desc, func(t *testing.T) {
175-
synctest.Test(t, func(t *testing.T) {
176-
instanceId := "foo-bar"
177-
instanceState := tt.instanceState
17894

179-
apiClient := newAPIMock(mockSettings{
180-
instanceId: &instanceId,
181-
instanceState: &instanceState,
182-
instanceGetFails: tt.instanceGetFails,
183-
})
95+
handlers := map[string]func(context.Context, sqlserverflex.DefaultAPI, string, string, string) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse]{
96+
"common logic": createOrUpdateInstanceWaitHandler,
97+
"create": CreateInstanceWaitHandler,
98+
"update": UpdateInstanceWaitHandler,
99+
}
184100

185-
var wantRes *sqlserverflex.GetInstanceResponse
186-
if tt.wantResp {
187-
wantRes = &sqlserverflex.GetInstanceResponse{
188-
Item: &sqlserverflex.Instance{
189-
Id: &instanceId,
190-
Status: utils.Ptr(tt.instanceState),
191-
},
101+
for handlerDesc, handlerFn := range handlers {
102+
for _, tt := range tests {
103+
t.Run(fmt.Sprintf("%s - %s", handlerDesc, tt.desc), func(t *testing.T) {
104+
synctest.Test(t, func(t *testing.T) {
105+
instanceId := "foo-bar"
106+
107+
apiClient := newAPIMock(mockSettings{
108+
instanceGetFails: tt.instanceGetFails,
109+
instanceId: &instanceId,
110+
instanceState: &tt.instanceState,
111+
})
112+
113+
var wantRes *sqlserverflex.GetInstanceResponse
114+
if tt.wantResp {
115+
wantRes = &sqlserverflex.GetInstanceResponse{
116+
Item: &sqlserverflex.Instance{
117+
Id: &instanceId,
118+
Status: utils.Ptr(tt.instanceState),
119+
},
120+
}
192121
}
193-
}
194122

195-
handler := UpdateInstanceWaitHandler(context.Background(), apiClient, "", instanceId, "")
123+
handler := handlerFn(context.Background(), apiClient, "", instanceId, "")
124+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background())
196125

197-
gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background())
198-
199-
if (err != nil) != tt.wantErr {
200-
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
201-
}
202-
if !cmp.Equal(gotRes, wantRes) {
203-
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
204-
}
126+
if (err != nil) != tt.wantErr {
127+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
128+
}
129+
diff := cmp.Diff(gotRes, wantRes)
130+
if diff != "" {
131+
t.Fatalf("handler gotRes = %+v\n want %+v\n diff = %s", gotRes, wantRes, diff)
132+
}
133+
})
205134
})
206-
})
135+
}
207136
}
208137
}
209138

0 commit comments

Comments
 (0)