Skip to content

Commit 5ed3181

Browse files
committed
add iaasalpha wait handler
1 parent d8a168a commit 5ed3181

File tree

3 files changed

+303
-1
lines changed

3 files changed

+303
-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: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package wait
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"time"
8+
9+
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
10+
"github.com/stackitcloud/stackit-sdk-go/core/wait"
11+
"github.com/stackitcloud/stackit-sdk-go/services/iaasalpha"
12+
)
13+
14+
const (
15+
CreateSuccess = "CREATED"
16+
)
17+
18+
// Interfaces needed for tests
19+
type APIClientInterface interface {
20+
GetNetworkExecute(ctx context.Context, projectId, region, networkId string) (*iaasalpha.Network, error)
21+
}
22+
23+
// CreateNetworkWaitHandler will wait for network creation using network id
24+
func CreateNetworkWaitHandler(ctx context.Context, a APIClientInterface, projectId, region, networkId string) *wait.AsyncActionHandler[iaasalpha.Network] {
25+
handler := wait.New(func() (waitFinished bool, response *iaasalpha.Network, err error) {
26+
network, err := a.GetNetworkExecute(ctx, projectId, region, networkId)
27+
if err != nil {
28+
return false, network, err
29+
}
30+
if network.Id == nil || network.Status == nil {
31+
return false, network, fmt.Errorf("crate failed for network with id %s, the response is not valid: the id or the state are missing", networkId)
32+
}
33+
// The state returns to "CREATED" after a successful creation is completed
34+
if *network.Id == networkId && *network.Status == CreateSuccess {
35+
return true, network, nil
36+
}
37+
return false, network, nil
38+
})
39+
handler.SetSleepBeforeWait(2 * time.Second)
40+
handler.SetTimeout(15 * time.Minute)
41+
return handler
42+
}
43+
44+
// UpdateNetworkWaitHandler will wait for network update
45+
func UpdateNetworkWaitHandler(ctx context.Context, a APIClientInterface, projectId, region, networkId string) *wait.AsyncActionHandler[iaasalpha.Network] {
46+
handler := wait.New(func() (waitFinished bool, response *iaasalpha.Network, err error) {
47+
network, err := a.GetNetworkExecute(ctx, projectId, region, networkId)
48+
if err != nil {
49+
return false, network, err
50+
}
51+
if network.Id == nil || network.Status == nil {
52+
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)
53+
}
54+
// The state returns to "CREATED" after a successful update is completed
55+
if *network.Id == networkId && *network.Status == CreateSuccess {
56+
return true, network, nil
57+
}
58+
return false, network, nil
59+
})
60+
handler.SetSleepBeforeWait(2 * time.Second)
61+
handler.SetTimeout(15 * time.Minute)
62+
return handler
63+
}
64+
65+
// DeleteNetworkWaitHandler will wait for network deletion
66+
func DeleteNetworkWaitHandler(ctx context.Context, a APIClientInterface, projectId, region, networkId string) *wait.AsyncActionHandler[iaasalpha.Network] {
67+
handler := wait.New(func() (waitFinished bool, response *iaasalpha.Network, err error) {
68+
network, err := a.GetNetworkExecute(ctx, projectId, region, networkId)
69+
if err == nil {
70+
return false, nil, nil
71+
}
72+
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
73+
if !ok {
74+
return false, network, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError: %w", err)
75+
}
76+
if oapiErr.StatusCode != http.StatusNotFound {
77+
return false, network, err
78+
}
79+
return true, nil, nil
80+
})
81+
handler.SetTimeout(15 * time.Minute)
82+
return handler
83+
}
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)