Skip to content

Commit 3ba928d

Browse files
Request waiter implementation
1 parent c64e434 commit 3ba928d

File tree

2 files changed

+175
-5
lines changed

2 files changed

+175
-5
lines changed

services/iaasalpha/wait/wait.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,23 @@ const (
1717
ErrorStatus = "ERROR"
1818
ServerActiveStatus = "ACTIVE"
1919
ServerResizingStatus = "RESIZING"
20+
21+
RequestCreateAction = "CREATE"
22+
RequestUpdateAction = "UPDATE"
23+
RequestDeleteAction = "DELETE"
24+
RequestCreatedStatus = "CREATED"
25+
RequestUpdatedStatus = "UPDATED"
26+
RequestDeletedStatus = "DELETED"
27+
RequestFailedStatus = "FAILED"
28+
29+
XRequestIDHeader = "X-Request-Id"
2030
)
2131

2232
// Interfaces needed for tests
2333
type APIClientInterface interface {
2434
GetVolumeExecute(ctx context.Context, projectId string, volumeId string) (*iaasalpha.Volume, error)
2535
GetServerExecute(ctx context.Context, projectId string, serverId string) (*iaasalpha.Server, error)
36+
GetProjectRequestExecute(ctx context.Context, projectId string, requestId string) (*iaasalpha.Request, error)
2637
}
2738

2839
// CreateVolumeWaitHandler will wait for volume creation
@@ -165,3 +176,51 @@ func DeleteServerWaitHandler(ctx context.Context, a APIClientInterface, projectI
165176
handler.SetTimeout(20 * time.Minute)
166177
return handler
167178
}
179+
180+
// ProjectRequestWaitHandler will wait for a request to succeed
181+
// It receives a request id that can be obtained from the x-request-id header in the http response of any operation in the IaaS API
182+
func ProjectRequestWaitHandler(ctx context.Context, a APIClientInterface, projectId, requestId string) *wait.AsyncActionHandler[iaasalpha.Request] {
183+
handler := wait.New(func() (waitFinished bool, response *iaasalpha.Request, err error) {
184+
request, err := a.GetProjectRequestExecute(ctx, projectId, requestId)
185+
if err != nil {
186+
return false, request, err
187+
}
188+
189+
if request == nil {
190+
return false, request, fmt.Errorf("request failed for request with id %s: nil response from GetProjectRequestExecute", requestId)
191+
}
192+
193+
if request.RequestId == nil || request.RequestAction == nil || request.Status == nil {
194+
return false, request, fmt.Errorf("request failed for request with id %s, the response is not valid: the id, the request action or the status are missing", requestId)
195+
}
196+
197+
if *request.RequestId != requestId {
198+
return false, request, fmt.Errorf("request failed for request with id %s: the response id doesn't match the request id", requestId)
199+
}
200+
201+
switch *request.RequestAction {
202+
case RequestCreateAction:
203+
if *request.Status == RequestCreatedStatus {
204+
return true, request, nil
205+
}
206+
case RequestUpdateAction:
207+
if *request.Status == RequestUpdatedStatus {
208+
return true, request, nil
209+
}
210+
case RequestDeleteAction:
211+
if *request.Status == RequestDeletedStatus {
212+
return true, request, nil
213+
}
214+
default:
215+
return false, request, fmt.Errorf("request failed for request with id %s, the request action %s is not supported", requestId, *request.RequestAction)
216+
}
217+
218+
if *request.Status == RequestFailedStatus {
219+
return true, request, fmt.Errorf("request failed for request with id %s", requestId)
220+
}
221+
222+
return false, request, nil
223+
})
224+
handler.SetTimeout(20 * time.Minute)
225+
return handler
226+
}

services/iaasalpha/wait/wait_test.go

Lines changed: 116 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import (
1212
)
1313

1414
type apiClientMocked struct {
15-
getVolumeFails bool
16-
getServerFails bool
17-
isDeleted bool
18-
resourceState string
19-
returnResizing bool
15+
getVolumeFails bool
16+
getServerFails bool
17+
getProjectRequestFails bool
18+
isDeleted bool
19+
resourceState string
20+
requestAction string
21+
returnResizing bool
2022
}
2123

2224
func (a *apiClientMocked) GetVolumeExecute(_ context.Context, _, _ string) (*iaasalpha.Volume, error) {
@@ -65,6 +67,20 @@ func (a *apiClientMocked) GetServerExecute(_ context.Context, _, _ string) (*iaa
6567
}, nil
6668
}
6769

70+
func (a *apiClientMocked) GetProjectRequestExecute(_ context.Context, _, _ string) (*iaasalpha.Request, error) {
71+
if a.getProjectRequestFails {
72+
return nil, &oapierror.GenericOpenAPIError{
73+
StatusCode: 500,
74+
}
75+
}
76+
77+
return &iaasalpha.Request{
78+
RequestId: utils.Ptr("rid"),
79+
RequestAction: &a.requestAction,
80+
Status: &a.resourceState,
81+
}, nil
82+
}
83+
6884
func TestCreateVolumeWaitHandler(t *testing.T) {
6985
tests := []struct {
7086
desc string
@@ -396,3 +412,98 @@ func TestResizeServerWaitHandler(t *testing.T) {
396412
})
397413
}
398414
}
415+
416+
func TestProjectRequestWaitHandler(t *testing.T) {
417+
tests := []struct {
418+
desc string
419+
getFails bool
420+
requestState string
421+
requestAction string
422+
wantErr bool
423+
wantResp bool
424+
}{
425+
{
426+
desc: "create_succeeded",
427+
getFails: false,
428+
requestAction: RequestCreateAction,
429+
requestState: RequestCreatedStatus,
430+
wantErr: false,
431+
wantResp: true,
432+
},
433+
{
434+
desc: "update_succeeded",
435+
getFails: false,
436+
requestAction: RequestUpdateAction,
437+
requestState: RequestUpdatedStatus,
438+
wantErr: false,
439+
wantResp: true,
440+
},
441+
{
442+
desc: "delete_succeeded",
443+
getFails: false,
444+
requestAction: RequestDeleteAction,
445+
requestState: RequestDeletedStatus,
446+
wantErr: false,
447+
wantResp: true,
448+
},
449+
{
450+
desc: "unsupported_action",
451+
getFails: false,
452+
requestAction: "OTHER_ACTION",
453+
wantErr: true,
454+
wantResp: true,
455+
},
456+
{
457+
desc: "error_status",
458+
getFails: false,
459+
requestAction: RequestCreateAction,
460+
requestState: ErrorStatus,
461+
wantErr: true,
462+
wantResp: true,
463+
},
464+
{
465+
desc: "get_fails",
466+
getFails: true,
467+
requestState: "",
468+
wantErr: true,
469+
wantResp: false,
470+
},
471+
{
472+
desc: "timeout",
473+
getFails: false,
474+
requestAction: RequestCreateAction,
475+
requestState: "ANOTHER Status",
476+
wantErr: true,
477+
wantResp: true,
478+
},
479+
}
480+
for _, tt := range tests {
481+
t.Run(tt.desc, func(t *testing.T) {
482+
apiClient := &apiClientMocked{
483+
getProjectRequestFails: tt.getFails,
484+
requestAction: tt.requestAction,
485+
resourceState: tt.requestState,
486+
}
487+
488+
var wantRes *iaasalpha.Request
489+
if tt.wantResp {
490+
wantRes = &iaasalpha.Request{
491+
RequestId: utils.Ptr("rid"),
492+
RequestAction: &tt.requestAction,
493+
Status: &tt.requestState,
494+
}
495+
}
496+
497+
handler := ProjectRequestWaitHandler(context.Background(), apiClient, "pid", "rid")
498+
499+
gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
500+
501+
if (err != nil) != tt.wantErr {
502+
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
503+
}
504+
if !cmp.Equal(gotRes, wantRes) {
505+
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
506+
}
507+
})
508+
}
509+
}

0 commit comments

Comments
 (0)