Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
## Release (2025-XX-XX)
## Release (2025-xx-xx)
- `scf`: [v0.2.1](services/scf/CHANGELOG.md#v021)
- **Feature:** Add waiter for deletion of organization
- `iaas`: [v0.29.1](services/iaas/CHANGELOG.md#v0291)
- **Bugfix:** Parsing oneOf with enum and string value

Expand Down
3 changes: 3 additions & 0 deletions services/scf/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## v0.2.1
- **Feature:** Add waiter for deletion of organization

## v0.2.0
- **Feature:** Add field `OrgId` in model `OrgManager`
- **Feature:** Add new model `OrganizationCreateBffResponse` and `SpaceCreatedBffResponse`
Expand Down
2 changes: 1 addition & 1 deletion services/scf/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.2.0
v0.2.1
44 changes: 44 additions & 0 deletions services/scf/wait/wait.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package wait

import (
"context"
"errors"
"fmt"
"net/http"
"time"

"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/core/wait"
"github.com/stackitcloud/stackit-sdk-go/services/scf"
)

const statusDeletingFailed = "deleting_failed"

// Interfaces needed for tests
type APIClientInterface interface {
GetOrganizationExecute(ctx context.Context, projectId, region, orgId string) (*scf.Organization, error)
}

// DeleteOrganizationWaitHandler will wait for Organization deletion
func DeleteOrganizationWaitHandler(ctx context.Context, a APIClientInterface, projectId, region, orgId string) *wait.AsyncActionHandler[scf.Organization] {
handler := wait.New(func() (waitFinished bool, response *scf.Organization, err error) {
s, err := a.GetOrganizationExecute(ctx, projectId, region, orgId)
if err != nil {
var oapiErr *oapierror.GenericOpenAPIError
ok := errors.As(err, &oapiErr)
if ok && oapiErr.StatusCode == http.StatusNotFound {
return true, s, nil
}
return false, s, err
}
if s == nil {
return false, nil, errors.New("organization is nil")
}
if *s.Status == statusDeletingFailed {
return true, nil, fmt.Errorf("delete failed for Organization with id %s", orgId)
}
return false, s, nil
})
handler.SetTimeout(20 * time.Minute)
return handler
}
99 changes: 99 additions & 0 deletions services/scf/wait/wait_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package wait

import (
"context"
"testing"
"time"

"github.com/google/uuid"

"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/scf"
)

var PROJECT_ID = uuid.New().String()
var INSTANCE_ID = uuid.New().String()

const REGION = "eu01"

type apiClientMocked struct {
getFails bool
errorCode int
returnInstance bool
projectId string
instanceId string
getSCFResponse *scf.Organization
}

func (a *apiClientMocked) GetOrganizationExecute(_ context.Context, _, _, _ string) (*scf.Organization, error) {
if a.getFails {
return nil, &oapierror.GenericOpenAPIError{
StatusCode: a.errorCode,
}
}
if !a.returnInstance {
return nil, nil
}
return a.getSCFResponse, nil
}

func TestDeleteOrganizationWaitHandler(t *testing.T) {
statusDeletingFailed := "deleting_failed"
tests := []struct {
desc string
wantErr bool
wantReturnedInstance bool
getFails bool
errorCode int
returnInstance bool
getOrgResponse *scf.Organization
}{
{
desc: "Instance deletion failed with error",
wantErr: true,
getFails: true,
},
{
desc: "Instance is not found",
wantErr: false,
getFails: true,
errorCode: 404,
},
{
desc: "Instance is in error state",
wantErr: true,
returnInstance: true,
getOrgResponse: &scf.Organization{
Status: &statusDeletingFailed,
},
},
{
desc: "Instance is nil",
wantErr: true,
returnInstance: true,
getOrgResponse: nil,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
apiClient := &apiClientMocked{
projectId: PROJECT_ID,
instanceId: INSTANCE_ID,
getFails: tt.getFails,
errorCode: tt.errorCode,
returnInstance: tt.returnInstance,
getSCFResponse: tt.getOrgResponse,
}

handler := DeleteOrganizationWaitHandler(context.Background(), apiClient, apiClient.projectId, REGION, apiClient.instanceId)
response, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())

if (err != nil) != tt.wantErr {
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
}
if (response != nil) != tt.wantReturnedInstance {
t.Fatalf("handler gotRes = %v, want nil", response)
}
})
}
}
Loading