Skip to content

Commit 5438724

Browse files
authored
feat: add iaasalpha wait handler (#3022)
* add iaasalpha wait handler
1 parent 41d4448 commit 5438724

File tree

3 files changed

+305
-1
lines changed

3 files changed

+305
-1
lines changed

services/iaasalpha/go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ module github.com/stackitcloud/stackit-sdk-go/services/iaasalpha
22

33
go 1.21
44

5-
require github.com/stackitcloud/stackit-sdk-go/core v0.17.2
5+
require (
6+
github.com/google/go-cmp v0.7.0
7+
github.com/stackitcloud/stackit-sdk-go/core v0.17.2
8+
)
69

710
require (
811
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect

services/iaasalpha/wait/wait.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package wait
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"net/http"
8+
"time"
9+
10+
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
11+
"github.com/stackitcloud/stackit-sdk-go/core/wait"
12+
"github.com/stackitcloud/stackit-sdk-go/services/iaasalpha"
13+
)
14+
15+
const (
16+
CreateSuccess = "CREATED"
17+
)
18+
19+
// Interfaces needed for tests
20+
type APIClientInterface interface {
21+
GetNetworkExecute(ctx context.Context, projectId, region, networkId string) (*iaasalpha.Network, error)
22+
}
23+
24+
// CreateNetworkWaitHandler will wait for network creation using network id
25+
func CreateNetworkWaitHandler(ctx context.Context, a APIClientInterface, projectId, region, networkId string) *wait.AsyncActionHandler[iaasalpha.Network] {
26+
handler := wait.New(func() (waitFinished bool, response *iaasalpha.Network, err error) {
27+
network, err := a.GetNetworkExecute(ctx, projectId, region, networkId)
28+
if err != nil {
29+
return false, network, err
30+
}
31+
if network.Id == nil || network.Status == nil {
32+
return false, network, fmt.Errorf("create failed for network with id %s, the response is not valid: the id or the state are missing", networkId)
33+
}
34+
// The state returns to "CREATED" after a successful creation is completed
35+
if *network.Id == networkId && *network.Status == CreateSuccess {
36+
return true, network, nil
37+
}
38+
return false, network, nil
39+
})
40+
handler.SetSleepBeforeWait(2 * time.Second)
41+
handler.SetTimeout(15 * time.Minute)
42+
return handler
43+
}
44+
45+
// UpdateNetworkWaitHandler will wait for network update
46+
func UpdateNetworkWaitHandler(ctx context.Context, a APIClientInterface, projectId, region, networkId string) *wait.AsyncActionHandler[iaasalpha.Network] {
47+
handler := wait.New(func() (waitFinished bool, response *iaasalpha.Network, err error) {
48+
network, err := a.GetNetworkExecute(ctx, projectId, region, networkId)
49+
if err != nil {
50+
return false, network, err
51+
}
52+
if network.Id == nil || network.Status == nil {
53+
return false, network, fmt.Errorf("update failed for network with id %s, the response is not valid: the id or the state are missing", networkId)
54+
}
55+
// The state returns to "CREATED" after a successful update is completed
56+
if *network.Id == networkId && *network.Status == CreateSuccess {
57+
return true, network, nil
58+
}
59+
return false, network, nil
60+
})
61+
handler.SetSleepBeforeWait(2 * time.Second)
62+
handler.SetTimeout(15 * time.Minute)
63+
return handler
64+
}
65+
66+
// DeleteNetworkWaitHandler will wait for network deletion
67+
func DeleteNetworkWaitHandler(ctx context.Context, a APIClientInterface, projectId, region, networkId string) *wait.AsyncActionHandler[iaasalpha.Network] {
68+
handler := wait.New(func() (waitFinished bool, response *iaasalpha.Network, err error) {
69+
network, err := a.GetNetworkExecute(ctx, projectId, region, networkId)
70+
if err == nil {
71+
return false, nil, nil
72+
}
73+
var oapiErr *oapierror.GenericOpenAPIError
74+
ok := errors.As(err, &oapiErr)
75+
if !ok {
76+
return false, network, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError: %w", err)
77+
}
78+
if oapiErr.StatusCode != http.StatusNotFound {
79+
return false, network, err
80+
}
81+
return true, nil, nil
82+
})
83+
handler.SetTimeout(15 * time.Minute)
84+
return handler
85+
}
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
package wait
2+
3+
import (
4+
"context"
5+
"testing"
6+
"time"
7+
8+
"github.com/google/go-cmp/cmp"
9+
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
10+
"github.com/stackitcloud/stackit-sdk-go/core/utils"
11+
"github.com/stackitcloud/stackit-sdk-go/services/iaasalpha"
12+
)
13+
14+
type apiClientMocked struct {
15+
getNetworkFails bool
16+
isDeleted bool
17+
resourceState string
18+
}
19+
20+
func (a *apiClientMocked) GetNetworkExecute(_ context.Context, _, _, _ string) (*iaasalpha.Network, error) {
21+
if a.isDeleted {
22+
return nil, &oapierror.GenericOpenAPIError{
23+
StatusCode: 404,
24+
}
25+
}
26+
27+
if a.getNetworkFails {
28+
return nil, &oapierror.GenericOpenAPIError{
29+
StatusCode: 500,
30+
}
31+
}
32+
33+
return &iaasalpha.Network{
34+
Id: utils.Ptr("nid"),
35+
Status: &a.resourceState,
36+
}, nil
37+
}
38+
39+
func TestCreateNetworkWaitHandler(t *testing.T) {
40+
tests := []struct {
41+
desc string
42+
getFails bool
43+
resourceState string
44+
wantErr bool
45+
wantResp bool
46+
}{
47+
{
48+
desc: "create_succeeded",
49+
getFails: false,
50+
resourceState: CreateSuccess,
51+
wantErr: false,
52+
wantResp: true,
53+
},
54+
{
55+
desc: "get_fails",
56+
getFails: true,
57+
resourceState: "",
58+
wantErr: true,
59+
wantResp: false,
60+
},
61+
{
62+
desc: "timeout",
63+
getFails: false,
64+
resourceState: "ANOTHER STATE",
65+
wantErr: true,
66+
wantResp: true,
67+
},
68+
}
69+
for _, tt := range tests {
70+
t.Run(tt.desc, func(t *testing.T) {
71+
apiClient := &apiClientMocked{
72+
getNetworkFails: tt.getFails,
73+
resourceState: tt.resourceState,
74+
}
75+
76+
var wantRes *iaasalpha.Network
77+
if tt.wantResp {
78+
wantRes = &iaasalpha.Network{
79+
Id: utils.Ptr("nid"),
80+
Status: utils.Ptr(tt.resourceState),
81+
}
82+
}
83+
84+
handler := CreateNetworkWaitHandler(context.Background(), apiClient, "pid", "eu01", "nid")
85+
86+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background())
87+
88+
if (err != nil) != tt.wantErr {
89+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
90+
}
91+
if !cmp.Equal(gotRes, wantRes) {
92+
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
93+
}
94+
})
95+
}
96+
}
97+
98+
func TestUpdateNetworkWaitHandler(t *testing.T) {
99+
tests := []struct {
100+
desc string
101+
getFails bool
102+
resourceState string
103+
wantErr bool
104+
wantResp bool
105+
}{
106+
{
107+
desc: "update_succeeded",
108+
getFails: false,
109+
resourceState: CreateSuccess,
110+
wantErr: false,
111+
wantResp: true,
112+
},
113+
{
114+
desc: "get_fails",
115+
getFails: true,
116+
resourceState: "",
117+
wantErr: true,
118+
wantResp: false,
119+
},
120+
{
121+
desc: "timeout",
122+
getFails: false,
123+
resourceState: "ANOTHER STATE",
124+
wantErr: true,
125+
wantResp: true,
126+
},
127+
}
128+
for _, tt := range tests {
129+
t.Run(tt.desc, func(t *testing.T) {
130+
apiClient := &apiClientMocked{
131+
getNetworkFails: tt.getFails,
132+
resourceState: tt.resourceState,
133+
}
134+
135+
var wantRes *iaasalpha.Network
136+
if tt.wantResp {
137+
wantRes = &iaasalpha.Network{
138+
Id: utils.Ptr("nid"),
139+
Status: utils.Ptr(tt.resourceState),
140+
}
141+
}
142+
143+
handler := UpdateNetworkWaitHandler(context.Background(), apiClient, "pid", "eu01", "nid")
144+
145+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background())
146+
147+
if (err != nil) != tt.wantErr {
148+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
149+
}
150+
if !cmp.Equal(gotRes, wantRes) {
151+
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
152+
}
153+
})
154+
}
155+
}
156+
157+
func TestDeleteNetworkWaitHandler(t *testing.T) {
158+
tests := []struct {
159+
desc string
160+
getFails bool
161+
isDeleted bool
162+
resourceState string
163+
wantErr bool
164+
wantResp bool
165+
}{
166+
{
167+
desc: "delete_succeeded",
168+
getFails: false,
169+
isDeleted: true,
170+
wantErr: false,
171+
wantResp: false,
172+
},
173+
{
174+
desc: "get_fails",
175+
getFails: true,
176+
resourceState: "",
177+
wantErr: true,
178+
wantResp: false,
179+
},
180+
{
181+
desc: "timeout",
182+
getFails: false,
183+
resourceState: "ANOTHER STATE",
184+
wantErr: true,
185+
wantResp: false,
186+
},
187+
}
188+
for _, tt := range tests {
189+
t.Run(tt.desc, func(t *testing.T) {
190+
apiClient := &apiClientMocked{
191+
getNetworkFails: tt.getFails,
192+
isDeleted: tt.isDeleted,
193+
resourceState: tt.resourceState,
194+
}
195+
196+
var wantRes *iaasalpha.Network
197+
if tt.wantResp {
198+
wantRes = &iaasalpha.Network{
199+
Id: utils.Ptr("nid"),
200+
Status: utils.Ptr(tt.resourceState),
201+
}
202+
}
203+
204+
handler := DeleteNetworkWaitHandler(context.Background(), apiClient, "pid", "eu01", "nid")
205+
206+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
207+
208+
if (err != nil) != tt.wantErr {
209+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
210+
}
211+
if !cmp.Equal(gotRes, wantRes) {
212+
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
213+
}
214+
})
215+
}
216+
}

0 commit comments

Comments
 (0)