Skip to content

Commit 13fc11e

Browse files
committed
implement new waiters
1 parent 213300a commit 13fc11e

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
resourcemanager "github.com/stackitcloud/stackit-sdk-go/services/resourcemanager/v0api"
12+
)
13+
14+
// CreateProjectWaitHandler will wait for project creation
15+
func CreateProjectWaitHandler(ctx context.Context, a resourcemanager.DefaultAPI, containerId string) *wait.AsyncActionHandler[resourcemanager.GetProjectResponse] {
16+
handler := wait.New(func() (waitFinished bool, response *resourcemanager.GetProjectResponse, err error) {
17+
p, _, err := a.GetProject(ctx, containerId).Execute()
18+
if err != nil {
19+
return false, nil, err
20+
}
21+
if p.ContainerId == containerId && p.LifecycleState == resourcemanager.LIFECYCLESTATE_ACTIVE {
22+
return true, p, nil
23+
}
24+
if p.ContainerId == containerId && p.LifecycleState == resourcemanager.LIFECYCLESTATE_CREATING {
25+
return false, nil, nil
26+
}
27+
return true, p, fmt.Errorf("creation failed: received project state '%s'", p.LifecycleState)
28+
})
29+
handler.SetSleepBeforeWait(1 * time.Minute)
30+
handler.SetTimeout(45 * time.Minute)
31+
return handler
32+
}
33+
34+
// DeleteProjectWaitHandler will wait for project deletion
35+
func DeleteProjectWaitHandler(ctx context.Context, a resourcemanager.DefaultAPI, containerId string) *wait.AsyncActionHandler[struct{}] {
36+
handler := wait.New(func() (waitFinished bool, response *struct{}, err error) {
37+
_, _, err = a.GetProject(ctx, containerId).Execute()
38+
if err == nil {
39+
return false, nil, nil
40+
}
41+
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
42+
if !ok {
43+
return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError")
44+
}
45+
if oapiErr.StatusCode == http.StatusNotFound || oapiErr.StatusCode == http.StatusForbidden {
46+
return true, nil, nil
47+
}
48+
return false, nil, err
49+
})
50+
handler.SetTimeout(15 * time.Minute)
51+
return handler
52+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package wait
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"testing"
7+
"time"
8+
9+
"github.com/google/go-cmp/cmp"
10+
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
11+
"github.com/stackitcloud/stackit-sdk-go/core/utils"
12+
resourcemanager "github.com/stackitcloud/stackit-sdk-go/services/resourcemanager/v0api"
13+
)
14+
15+
type mockSettings struct {
16+
getFails bool
17+
getNotFound bool
18+
projectState resourcemanager.LifecycleState
19+
}
20+
21+
func newAPIMock(settings mockSettings) resourcemanager.DefaultAPI {
22+
return &resourcemanager.DefaultAPIServiceMock{
23+
GetProjectExecuteMock: utils.Ptr(func(r resourcemanager.ApiGetProjectRequest) (*resourcemanager.GetProjectResponse, *http.Response, error) {
24+
if settings.getFails {
25+
return nil, &http.Response{}, &oapierror.GenericOpenAPIError{
26+
StatusCode: http.StatusInternalServerError,
27+
}
28+
}
29+
30+
if settings.getNotFound {
31+
return nil, &http.Response{}, &oapierror.GenericOpenAPIError{
32+
StatusCode: http.StatusNotFound,
33+
}
34+
}
35+
36+
return &resourcemanager.GetProjectResponse{
37+
LifecycleState: settings.projectState,
38+
ContainerId: "cid",
39+
}, &http.Response{}, nil
40+
}),
41+
}
42+
}
43+
44+
func TestCreateProjectWaitHandler(t *testing.T) {
45+
tests := []struct {
46+
desc string
47+
getFails bool
48+
projectState resourcemanager.LifecycleState
49+
wantErr bool
50+
wantResp bool
51+
}{
52+
{
53+
desc: "create_succeeded",
54+
getFails: false,
55+
projectState: resourcemanager.LIFECYCLESTATE_ACTIVE,
56+
wantErr: false,
57+
wantResp: true,
58+
},
59+
{
60+
desc: "creating",
61+
getFails: false,
62+
projectState: resourcemanager.LIFECYCLESTATE_CREATING,
63+
wantErr: true,
64+
wantResp: false,
65+
},
66+
{
67+
desc: "get_fails",
68+
getFails: true,
69+
projectState: resourcemanager.LifecycleState(""),
70+
wantErr: true,
71+
wantResp: false,
72+
},
73+
{
74+
desc: "unknown_state",
75+
getFails: false,
76+
projectState: resourcemanager.LifecycleState("ANOTHER STATE"),
77+
wantErr: true,
78+
wantResp: true,
79+
},
80+
}
81+
for _, tt := range tests {
82+
t.Run(tt.desc, func(t *testing.T) {
83+
apiClient := newAPIMock(mockSettings{
84+
getFails: tt.getFails,
85+
projectState: tt.projectState,
86+
})
87+
88+
var wantRes *resourcemanager.GetProjectResponse
89+
if tt.wantResp {
90+
wantRes = &resourcemanager.GetProjectResponse{
91+
LifecycleState: tt.projectState,
92+
ContainerId: "cid",
93+
}
94+
}
95+
96+
handler := CreateProjectWaitHandler(context.Background(), apiClient, "cid")
97+
98+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(10 * time.Millisecond).WaitWithContext(context.Background())
99+
100+
if (err != nil) != tt.wantErr {
101+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
102+
}
103+
if !cmp.Equal(gotRes, wantRes) {
104+
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
105+
}
106+
})
107+
}
108+
}
109+
110+
func TestDeleteProjectWaitHandler(t *testing.T) {
111+
tests := []struct {
112+
desc string
113+
getFails bool
114+
getNotFound bool
115+
projectState resourcemanager.LifecycleState
116+
wantErr bool
117+
}{
118+
{
119+
desc: "delete_succeeded",
120+
getFails: false,
121+
getNotFound: true,
122+
projectState: resourcemanager.LifecycleState(""),
123+
wantErr: false,
124+
},
125+
{
126+
desc: "get_fails",
127+
getFails: true,
128+
projectState: "",
129+
wantErr: true,
130+
},
131+
{
132+
desc: "timeout",
133+
getFails: false,
134+
projectState: "ANOTHER STATE",
135+
wantErr: true,
136+
},
137+
}
138+
for _, tt := range tests {
139+
t.Run(tt.desc, func(t *testing.T) {
140+
apiClient := newAPIMock(mockSettings{
141+
getFails: tt.getFails,
142+
getNotFound: tt.getNotFound,
143+
projectState: tt.projectState,
144+
})
145+
146+
handler := DeleteProjectWaitHandler(context.Background(), apiClient, "cid")
147+
148+
_, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
149+
150+
if (err != nil) != tt.wantErr {
151+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
152+
}
153+
})
154+
}
155+
}

0 commit comments

Comments
 (0)