Skip to content

Commit f75de61

Browse files
peremanentFyusel
andauthored
Add waiters in git service for Create and Delete git instances (#1890)
* Add waiters in git service for Create and Delete git instances * Add waiters in git service for Create and Delete git instances * Modify Waiters tests for Create and Delete git instances * Improving waiters tests in git package * fix: misspelling of * Improve waiters test and adding changelog to the git service --------- Co-authored-by: Alexander Dahmen <[email protected]>
1 parent ad3fa15 commit f75de61

File tree

5 files changed

+296
-0
lines changed

5 files changed

+296
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
- **New**: STACKIT Git module can be used to manage STACKIT Git
99
- [v0.2.0](services/git/CHANGELOG.md#v020-2025-04-16)
1010
- **Features**: Add new methods to manage the STACKIT Git: `CreateInstance`, `DeleteInstance`, `GetInstance`
11+
- [v0.3.0](services/git/CHANGELOG.md#v030-2025-04-22)
12+
- **Features**: Add waiters to manage the STACKIT Git
1113
- `observability`: [v0.5.0](services/observability/CHANGELOG.md#v050-2025-04-16)
1214
- **Feature:** Add new methods `ListLogsAlertgroups`, `CreateLogsAlertgroups`, `GetLogsAlertgroup`, `UpdateLogsAlertgroup`, `DeleteLogsAlertgroup`
1315

services/git/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## v0.3.0 (2025-04-22)
2+
- **Features**: Add waiters to manage the STACKIT Git
3+
14
## v0.2.0 (2025-04-16)
25
- **Features**: Add new methods to manage the STACKIT Git: `CreateInstance`, `DeleteInstance`, `GetInstance`
36

services/git/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/stackitcloud/stackit-sdk-go/services/git
33
go 1.21
44

55
require (
6+
github.com/google/go-cmp v0.7.0
67
github.com/google/uuid v1.6.0
78
github.com/stackitcloud/stackit-sdk-go/core v0.17.1
89
)

services/git/wait/wait.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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/git"
13+
)
14+
15+
const (
16+
InstanceStateReady = "Ready"
17+
InstanceStateCreating = "Creating"
18+
InstanceStateError = "Error"
19+
)
20+
21+
// APIClientInterface Interfaces needed for tests
22+
type APIClientInterface interface {
23+
GetInstanceExecute(ctx context.Context, projectId string, instanceId string) (*git.Instance, error)
24+
}
25+
26+
func CreateGitInstanceWaitHandler(ctx context.Context, a APIClientInterface, projectId, instanceId string) *wait.AsyncActionHandler[git.Instance] {
27+
handler := wait.New(func() (waitFinished bool, response *git.Instance, err error) {
28+
instance, err := a.GetInstanceExecute(ctx, projectId, instanceId)
29+
if err != nil {
30+
return false, nil, err
31+
}
32+
if instance.Id == nil || instance.State == nil {
33+
return false, nil, fmt.Errorf("could not get Instance id or State from response for project %s and instanceId %s", projectId, instanceId)
34+
}
35+
if *instance.Id == instanceId && *instance.State == InstanceStateReady {
36+
return true, instance, nil
37+
}
38+
if *instance.Id == instanceId && *instance.State == InstanceStateError {
39+
return true, instance, fmt.Errorf("create failed for Instance with id %s", instanceId)
40+
}
41+
return false, nil, nil
42+
})
43+
handler.SetTimeout(10 * time.Minute)
44+
return handler
45+
}
46+
47+
func DeleteGitInstanceWaitHandler(ctx context.Context, a APIClientInterface, projectId, instanceId string) *wait.AsyncActionHandler[git.Instance] {
48+
handler := wait.New(func() (waitFinished bool, response *git.Instance, err error) {
49+
_, err = a.GetInstanceExecute(ctx, projectId, instanceId)
50+
// the instances is still gettable, e.g. not deleted, when the errors is null
51+
if err == nil {
52+
return false, nil, nil
53+
}
54+
var oapiError *oapierror.GenericOpenAPIError
55+
if errors.As(err, &oapiError) {
56+
if statusCode := oapiError.StatusCode; statusCode == http.StatusNotFound {
57+
return true, nil, nil
58+
}
59+
}
60+
return false, nil, err
61+
})
62+
handler.SetTimeout(10 * time.Minute)
63+
return handler
64+
}

services/git/wait/wait_test.go

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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/google/uuid"
11+
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
12+
"github.com/stackitcloud/stackit-sdk-go/core/utils"
13+
"github.com/stackitcloud/stackit-sdk-go/services/git"
14+
)
15+
16+
type apiClientMocked struct {
17+
getFails bool
18+
errorCode int
19+
returnInstance bool
20+
projectId string
21+
instanceId string
22+
getGitResponse *git.Instance
23+
}
24+
25+
func (a *apiClientMocked) GetInstanceExecute(_ context.Context, _, _ string) (*git.Instance, error) {
26+
if a.getFails {
27+
return nil, &oapierror.GenericOpenAPIError{
28+
StatusCode: a.errorCode,
29+
}
30+
}
31+
if !a.returnInstance {
32+
return nil, nil
33+
}
34+
return a.getGitResponse, nil
35+
}
36+
37+
var PROJECT_ID = uuid.New().String()
38+
var INSTANCE_ID = uuid.New().String()
39+
40+
func TestCreateGitInstanceWaitHandler(t *testing.T) {
41+
tests := []struct {
42+
desc string
43+
getFails bool
44+
wantErr bool
45+
wantResp bool
46+
projectId string
47+
instanceId string
48+
returnInstance bool
49+
getGitResponse *git.Instance
50+
}{
51+
{
52+
desc: "Creation of an instance succeeded",
53+
getFails: false,
54+
wantErr: false,
55+
wantResp: true,
56+
projectId: uuid.New().String(),
57+
instanceId: INSTANCE_ID,
58+
returnInstance: true,
59+
getGitResponse: &git.Instance{
60+
Created: utils.Ptr(time.Now()),
61+
Id: utils.Ptr(INSTANCE_ID),
62+
Name: utils.Ptr("instance-test"),
63+
State: utils.Ptr(InstanceStateReady),
64+
Url: utils.Ptr("https://testing.git.onstackit.cloud"),
65+
Version: utils.Ptr("v1.6.0"),
66+
},
67+
},
68+
{
69+
desc: "Creation of an instance failed with error",
70+
getFails: true,
71+
wantErr: true,
72+
wantResp: false,
73+
projectId: uuid.New().String(),
74+
instanceId: INSTANCE_ID,
75+
returnInstance: true,
76+
getGitResponse: &git.Instance{
77+
Created: utils.Ptr(time.Now()),
78+
Id: utils.Ptr(INSTANCE_ID),
79+
Name: utils.Ptr("instance-test"),
80+
State: utils.Ptr(InstanceStateReady),
81+
Url: utils.Ptr("https://testing.git.onstackit.cloud"),
82+
Version: utils.Ptr("v1.6.0"),
83+
},
84+
},
85+
{
86+
desc: "Creation of an instance with response failed and without error",
87+
getFails: false,
88+
wantErr: true,
89+
wantResp: true,
90+
projectId: uuid.New().String(),
91+
instanceId: INSTANCE_ID,
92+
returnInstance: true,
93+
getGitResponse: &git.Instance{
94+
Created: utils.Ptr(time.Now()),
95+
Id: utils.Ptr(INSTANCE_ID),
96+
Name: utils.Ptr("instance-test"),
97+
State: utils.Ptr(InstanceStateError),
98+
Url: utils.Ptr("https://testing.git.onstackit.cloud"),
99+
Version: utils.Ptr("v1.6.0"),
100+
},
101+
},
102+
{
103+
desc: "Creation of an instance failed without id on the response",
104+
getFails: false,
105+
wantErr: true,
106+
wantResp: false,
107+
projectId: PROJECT_ID,
108+
instanceId: INSTANCE_ID,
109+
returnInstance: true,
110+
getGitResponse: &git.Instance{
111+
Created: utils.Ptr(time.Now()),
112+
Name: utils.Ptr("instance-test"),
113+
State: utils.Ptr(InstanceStateError),
114+
Url: utils.Ptr("https://testing.git.onstackit.cloud"),
115+
Version: utils.Ptr("v1.6.0"),
116+
},
117+
},
118+
119+
{
120+
desc: "Creation of an instance without state on the response",
121+
getFails: false,
122+
wantErr: true,
123+
wantResp: false,
124+
projectId: PROJECT_ID,
125+
instanceId: INSTANCE_ID,
126+
returnInstance: true,
127+
getGitResponse: &git.Instance{
128+
Created: utils.Ptr(time.Now()),
129+
Id: utils.Ptr(INSTANCE_ID),
130+
Name: utils.Ptr("instance-test"),
131+
Url: utils.Ptr("https://testing.git.onstackit.cloud"),
132+
Version: utils.Ptr("v1.6.0"),
133+
},
134+
},
135+
}
136+
for _, tt := range tests {
137+
t.Run(tt.desc, func(t *testing.T) {
138+
apiClient := &apiClientMocked{
139+
getFails: tt.getFails,
140+
projectId: tt.projectId,
141+
instanceId: tt.instanceId,
142+
getGitResponse: tt.getGitResponse,
143+
returnInstance: tt.returnInstance,
144+
}
145+
var instanceWanted *git.Instance
146+
if tt.wantResp {
147+
instanceWanted = tt.getGitResponse
148+
}
149+
150+
handler := CreateGitInstanceWaitHandler(context.Background(), apiClient, apiClient.projectId, apiClient.instanceId)
151+
152+
response, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
153+
154+
if (err != nil) != tt.wantErr {
155+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
156+
}
157+
if !cmp.Equal(response, instanceWanted) {
158+
t.Fatalf("handler gotRes = %v, want %v", response, instanceWanted)
159+
}
160+
})
161+
}
162+
}
163+
164+
func TestDeleteGitInstanceWaitHandler(t *testing.T) {
165+
tests := []struct {
166+
desc string
167+
wantErr bool
168+
wantReturnedInstance bool
169+
getFails bool
170+
errorCode int
171+
returnInstance bool
172+
getGitResponse *git.Instance
173+
}{
174+
{
175+
desc: "Instance deletion failed with error",
176+
wantErr: true,
177+
getFails: true,
178+
},
179+
{
180+
desc: "Instance deletion failed returning existing instance",
181+
wantErr: true,
182+
getFails: false,
183+
184+
wantReturnedInstance: false,
185+
returnInstance: true,
186+
getGitResponse: &git.Instance{
187+
Created: utils.Ptr(time.Now()),
188+
Id: utils.Ptr(INSTANCE_ID),
189+
Name: utils.Ptr("instance-test"),
190+
State: utils.Ptr(InstanceStateReady),
191+
Url: utils.Ptr("https://testing.git.onstackit.cloud"),
192+
Version: utils.Ptr("v1.6.0"),
193+
},
194+
},
195+
{
196+
desc: "Instance deletion successful",
197+
wantErr: false,
198+
getFails: true,
199+
errorCode: http.StatusNotFound,
200+
wantReturnedInstance: false,
201+
returnInstance: false,
202+
},
203+
}
204+
for _, tt := range tests {
205+
t.Run(tt.desc, func(t *testing.T) {
206+
apiClient := &apiClientMocked{
207+
208+
projectId: uuid.New().String(),
209+
getFails: tt.getFails,
210+
errorCode: tt.errorCode,
211+
returnInstance: tt.returnInstance,
212+
getGitResponse: tt.getGitResponse,
213+
}
214+
215+
handler := DeleteGitInstanceWaitHandler(context.Background(), apiClient, apiClient.projectId, apiClient.instanceId)
216+
response, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
217+
218+
if (err != nil) != tt.wantErr {
219+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
220+
}
221+
if (response != nil) != tt.wantReturnedInstance {
222+
t.Fatalf("handler gotRes = %v, want nil", response)
223+
}
224+
})
225+
}
226+
}

0 commit comments

Comments
 (0)