From 7bee3082df9e5399fe8c4c2028c7bcb63e5763db Mon Sep 17 00:00:00 2001 From: Lee Farrell Date: Wed, 25 Aug 2021 10:21:37 +0100 Subject: [PATCH 1/2] add volume group crud operations --- pkg/service/ecloud/error.go | 9 + pkg/service/ecloud/model.go | 13 + .../ecloud/model_paginated_generated.go | 14 + .../ecloud/model_response_generated.go | 12 + pkg/service/ecloud/request.go | 12 + pkg/service/ecloud/service.go | 8 + pkg/service/ecloud/service_volumegroup.go | 193 ++++++++ .../ecloud/service_volumegroup_test.go | 439 ++++++++++++++++++ 8 files changed, 700 insertions(+) create mode 100644 pkg/service/ecloud/service_volumegroup.go create mode 100644 pkg/service/ecloud/service_volumegroup_test.go diff --git a/pkg/service/ecloud/error.go b/pkg/service/ecloud/error.go index 8c36e6b..670cb0d 100644 --- a/pkg/service/ecloud/error.go +++ b/pkg/service/ecloud/error.go @@ -343,3 +343,12 @@ type NetworkRulePortNotFoundError struct { func (e *NetworkRulePortNotFoundError) Error() string { return fmt.Sprintf("Network rule port not found with ID [%s]", e.ID) } + +// VolumeGroupNotFoundError indicates a volume group was not found +type VolumeGroupNotFoundError struct { + ID string +} + +func (e *VolumeGroupNotFoundError) Error() string { + return fmt.Sprintf("Volume group not found with ID [%s]", e.ID) +} \ No newline at end of file diff --git a/pkg/service/ecloud/model.go b/pkg/service/ecloud/model.go index b1e54d2..6906bd4 100644 --- a/pkg/service/ecloud/model.go +++ b/pkg/service/ecloud/model.go @@ -976,3 +976,16 @@ type NetworkRulePort struct { CreatedAt connection.DateTime `json:"created_at"` UpdatedAt connection.DateTime `json:"updated_at"` } + +// VolumeGroup represents an eCloud volume group resource +// +genie:model_response +// +genie:model_paginated +type VolumeGroup struct { + ID string `json:"id"` + Name string `json:"name"` + VPCID string `json:"vpc_id"` + AvailabilityZoneID string `json:"availability_zone_id"` + Status TaskStatus `json:"status"` + CreatedAt connection.DateTime `json:"created_at"` + UpdatedAt connection.DateTime `json:"updated_at"` +} diff --git a/pkg/service/ecloud/model_paginated_generated.go b/pkg/service/ecloud/model_paginated_generated.go index 45ec92d..b522a60 100644 --- a/pkg/service/ecloud/model_paginated_generated.go +++ b/pkg/service/ecloud/model_paginated_generated.go @@ -589,3 +589,17 @@ func NewPaginatedNetworkRulePort(getFunc connection.PaginatedGetFunc, parameters PaginatedBase: connection.NewPaginatedBase(parameters, pagination, getFunc), } } + +// PaginatedVolumeGroup represents a paginated collection of VolumeGroup +type PaginatedVolumeGroup struct { + *connection.PaginatedBase + Items []VolumeGroup +} + +// NewPaginatedVolumeGroup returns a pointer to an initialized PaginatedVolumeGroup struct +func NewPaginatedVolumeGroup(getFunc connection.PaginatedGetFunc, parameters connection.APIRequestParameters, pagination connection.APIResponseMetadataPagination, items []VolumeGroup) *PaginatedVolumeGroup { + return &PaginatedVolumeGroup{ + Items: items, + PaginatedBase: connection.NewPaginatedBase(parameters, pagination, getFunc), + } +} diff --git a/pkg/service/ecloud/model_response_generated.go b/pkg/service/ecloud/model_response_generated.go index fd25b5b..9e6ad6d 100644 --- a/pkg/service/ecloud/model_response_generated.go +++ b/pkg/service/ecloud/model_response_generated.go @@ -541,3 +541,15 @@ type GetNetworkRulePortResponseBody struct { connection.APIResponseBody Data NetworkRulePort `json:"data"` } + +// GetVolumeGroupSliceResponseBody represents an API response body containing []VolumeGroup data +type GetVolumeGroupSliceResponseBody struct { + connection.APIResponseBody + Data []VolumeGroup `json:"data"` +} + +// GetVolumeGroupResponseBody represents an API response body containing VolumeGroup data +type GetVolumeGroupResponseBody struct { + connection.APIResponseBody + Data VolumeGroup `json:"data"` +} diff --git a/pkg/service/ecloud/request.go b/pkg/service/ecloud/request.go index 507771a..22c1230 100644 --- a/pkg/service/ecloud/request.go +++ b/pkg/service/ecloud/request.go @@ -474,3 +474,15 @@ type PatchNetworkRulePortRequest struct { type MigrateInstanceRequest struct { HostGroupID string `json:"host_group_id"` } + +// CreateVolumeGroupRequest represents a request to create a volume group +type CreateVolumeGroupRequest struct { + Name string `json:"name,omitempty"` + VPCID string `json:"vpc_id"` + AvailabilityZoneID string `json:"availability_zone_id"` +} + +// PatchVolumeGroupRequest represents a request to patch a volume group +type PatchVolumeGroupRequest struct { + Name string `json:"name,omitempty"` +} diff --git a/pkg/service/ecloud/service.go b/pkg/service/ecloud/service.go index 3fc509f..e5934d3 100644 --- a/pkg/service/ecloud/service.go +++ b/pkg/service/ecloud/service.go @@ -350,6 +350,14 @@ type ECloudService interface { CreateNetworkRulePort(req CreateNetworkRulePortRequest) (TaskReference, error) PatchNetworkRulePort(ruleID string, req PatchNetworkRulePortRequest) (TaskReference, error) DeleteNetworkRulePort(ruleID string) (string, error) + + //Volume Groups + GetVolumeGroups(parameters connection.APIRequestParameters) ([]VolumeGroup, error) + GetVolumeGroupsPaginated(parameters connection.APIRequestParameters) (*PaginatedVolumeGroup, error) + GetVolumeGroup(groupID string) (VolumeGroup, error) + CreateVolumeGroup(req CreateVolumeGroupRequest) (TaskReference, error) + PatchVolumeGroup(groupID string, patch PatchVolumeGroupRequest) (TaskReference, error) + DeleteVolumeGroup(groupID string) (string, error) } // Service implements ECloudService for managing diff --git a/pkg/service/ecloud/service_volumegroup.go b/pkg/service/ecloud/service_volumegroup.go new file mode 100644 index 0000000..3c2c0c5 --- /dev/null +++ b/pkg/service/ecloud/service_volumegroup.go @@ -0,0 +1,193 @@ +package ecloud + +import ( + "fmt" + + "github.com/ukfast/sdk-go/pkg/connection" +) + +// GetVolumeGroups retrieves a list of volume groups +func (s *Service) GetVolumeGroups(parameters connection.APIRequestParameters) ([]VolumeGroup, error) { + var volGroups []VolumeGroup + + getFunc := func(p connection.APIRequestParameters) (connection.Paginated, error) { + return s.GetVolumeGroupsPaginated(p) + } + + responseFunc := func(response connection.Paginated) { + for _, volumeGroup := range response.(*PaginatedVolumeGroup).Items { + volGroups = append(volGroups, volumeGroup) + } + } + + return volGroups, connection.InvokeRequestAll(getFunc, responseFunc, parameters) +} + +// GetVolumeGroupsPaginated retrieves a paginated list of volume groups +func (s *Service) GetVolumeGroupsPaginated(parameters connection.APIRequestParameters) (*PaginatedVolumeGroup, error) { + body, err := s.getVolumeGroupsPaginatedResponseBody(parameters) + + return NewPaginatedVolumeGroup(func(p connection.APIRequestParameters) (connection.Paginated, error) { + return s.GetVolumeGroupsPaginated(p) + }, parameters, body.Metadata.Pagination, body.Data), err +} + +func (s *Service) getVolumeGroupsPaginatedResponseBody(parameters connection.APIRequestParameters) (*GetVolumeGroupSliceResponseBody, error) { + body := &GetVolumeGroupSliceResponseBody{} + + response, err := s.connection.Get("/ecloud/v2/volume-groups", parameters) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, nil) +} + +// GetVolumeGroup retrieves a single volumeGroup by id +func (s *Service) GetVolumeGroup(volumeGroupID string) (VolumeGroup, error) { + body, err := s.getVolumeGroupResponseBody(volumeGroupID) + + return body.Data, err +} + +func (s *Service) getVolumeGroupResponseBody(volumeGroupID string) (*GetVolumeGroupResponseBody, error) { + body := &GetVolumeGroupResponseBody{} + + if volumeGroupID == "" { + return body, fmt.Errorf("invalid volume group id") + } + + response, err := s.connection.Get(fmt.Sprintf("/ecloud/v2/volume-groups/%s", volumeGroupID), connection.APIRequestParameters{}) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { + if response.StatusCode == 404 { + return &VolumeGroupNotFoundError{ID: volumeGroupID} + } + + return nil + }) +} + +// CreateVolumeGroup creates a volumeGroup +func (s *Service) CreateVolumeGroup(req CreateVolumeGroupRequest) (TaskReference, error) { + body, err := s.createVolumeGroupResponseBody(req) + + return body.Data, err +} + +func (s *Service) createVolumeGroupResponseBody(req CreateVolumeGroupRequest) (*GetTaskReferenceResponseBody, error) { + body := &GetTaskReferenceResponseBody{} + + response, err := s.connection.Post("/ecloud/v2/volume-groups", &req) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, nil) +} + +// PatchVolumeGroup patches a volumeGroup +func (s *Service) PatchVolumeGroup(volumeGroupID string, req PatchVolumeGroupRequest) (TaskReference, error) { + body, err := s.patchVolumeGroupResponseBody(volumeGroupID, req) + + return body.Data, err +} + +func (s *Service) patchVolumeGroupResponseBody(volumeGroupID string, req PatchVolumeGroupRequest) (*GetTaskReferenceResponseBody, error) { + body := &GetTaskReferenceResponseBody{} + + if volumeGroupID == "" { + return body, fmt.Errorf("invalid volume group id") + } + + response, err := s.connection.Patch(fmt.Sprintf("/ecloud/v2/volume-groups/%s", volumeGroupID), &req) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { + if response.StatusCode == 404 { + return &VolumeGroupNotFoundError{ID: volumeGroupID} + } + + return nil + }) +} + +// DeleteVolumeGroup deletes a volumeGroup +func (s *Service) DeleteVolumeGroup(volumeGroupID string) (string, error) { + body, err := s.deleteVolumeGroupResponseBody(volumeGroupID) + + return body.Data.TaskID, err +} + +func (s *Service) deleteVolumeGroupResponseBody(volumeGroupID string) (*GetTaskReferenceResponseBody, error) { + body := &GetTaskReferenceResponseBody{} + + if volumeGroupID == "" { + return body, fmt.Errorf("invalid volume group id") + } + + response, err := s.connection.Delete(fmt.Sprintf("/ecloud/v2/volume-groups/%s", volumeGroupID), nil) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { + if response.StatusCode == 404 { + return &VolumeGroupNotFoundError{ID: volumeGroupID} + } + + return nil + }) +} + +// GetVolumeGroupTasks retrieves a list of VolumeGroup tasks +func (s *Service) GetVolumeGroupTasks(volumeGroupID string, parameters connection.APIRequestParameters) ([]Task, error) { + var tasks []Task + + getFunc := func(p connection.APIRequestParameters) (connection.Paginated, error) { + return s.GetVolumeGroupTasksPaginated(volumeGroupID, p) + } + + responseFunc := func(response connection.Paginated) { + for _, task := range response.(*PaginatedTask).Items { + tasks = append(tasks, task) + } + } + + return tasks, connection.InvokeRequestAll(getFunc, responseFunc, parameters) +} + +// GetVolumeGroupTasksPaginated retrieves a paginated list of VolumeGroup tasks +func (s *Service) GetVolumeGroupTasksPaginated(volumeGroupID string, parameters connection.APIRequestParameters) (*PaginatedTask, error) { + body, err := s.getVolumeGroupTasksPaginatedResponseBody(volumeGroupID, parameters) + + return NewPaginatedTask(func(p connection.APIRequestParameters) (connection.Paginated, error) { + return s.GetVolumeGroupTasksPaginated(volumeGroupID, p) + }, parameters, body.Metadata.Pagination, body.Data), err +} + +func (s *Service) getVolumeGroupTasksPaginatedResponseBody(volumeGroupID string, parameters connection.APIRequestParameters) (*GetTaskSliceResponseBody, error) { + body := &GetTaskSliceResponseBody{} + + if volumeGroupID == "" { + return body, fmt.Errorf("invalid volume group id") + } + + response, err := s.connection.Get(fmt.Sprintf("/ecloud/v2/volume-groups/%s/tasks", volumeGroupID), parameters) + if err != nil { + return body, err + } + + return body, response.HandleResponse(body, func(resp *connection.APIResponse) error { + if response.StatusCode == 404 { + return &VolumeGroupNotFoundError{ID: volumeGroupID} + } + + return nil + }) +} diff --git a/pkg/service/ecloud/service_volumegroup_test.go b/pkg/service/ecloud/service_volumegroup_test.go new file mode 100644 index 0000000..ce877bd --- /dev/null +++ b/pkg/service/ecloud/service_volumegroup_test.go @@ -0,0 +1,439 @@ +package ecloud + +import ( + "bytes" + "errors" + "io/ioutil" + "net/http" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/ukfast/sdk-go/pkg/connection" + "github.com/ukfast/sdk-go/test/mocks" +) + +func TestGetVolumeGroups(t *testing.T) { + t.Run("Single", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Get("/ecloud/v2/volume-groups", gomock.Any()).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":[{\"id\":\"volgroup-abcdef12\"}],\"meta\":{\"pagination\":{\"total_pages\":1}}}"))), + StatusCode: 200, + }, + }, nil).Times(1) + + volumeGroups, err := s.GetVolumeGroups(connection.APIRequestParameters{}) + + assert.Nil(t, err) + assert.Len(t, volumeGroups, 1) + assert.Equal(t, "volgroup-abcdef12", volumeGroups[0].ID) + }) + + t.Run("ConnectionError_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Get("/ecloud/v2/volume-groups", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")) + + _, err := s.GetVolumeGroups(connection.APIRequestParameters{}) + + assert.NotNil(t, err) + assert.Equal(t, "test error 1", err.Error()) + }) +} + +func TestGetVolumeGroup(t *testing.T) { + t.Run("Valid", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12", gomock.Any()).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"volgroup-abcdef12\"}}"))), + StatusCode: 200, + }, + }, nil).Times(1) + + volumeGroup, err := s.GetVolumeGroup("volgroup-abcdef12") + + assert.Nil(t, err) + assert.Equal(t, "volgroup-abcdef12", volumeGroup.ID) + }) + + t.Run("ConnectionError_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) + + _, err := s.GetVolumeGroup("volgroup-abcdef12") + + assert.NotNil(t, err) + assert.Equal(t, "test error 1", err.Error()) + }) + + t.Run("InvalidVolumeGroupID_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + _, err := s.GetVolumeGroup("") + + assert.NotNil(t, err) + assert.Equal(t, "invalid volume group id", err.Error()) + }) + + t.Run("404_ReturnsVolumeGroupNotFoundError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12", gomock.Any()).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + StatusCode: 404, + }, + }, nil).Times(1) + + _, err := s.GetVolumeGroup("volgroup-abcdef12") + + assert.NotNil(t, err) + assert.IsType(t, &VolumeGroupNotFoundError{}, err) + }) +} + +func TestCreateVolumeGroup(t *testing.T) { + t.Run("Valid", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + req := CreateVolumeGroupRequest{ + Name: "some name", + } + + c.EXPECT().Post("/ecloud/v2/volume-groups", &req).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"id\":\"volgroup-abcdef12\",\"task_id\":\"task-abcdef12\"}}"))), + StatusCode: 202, + }, + }, nil).Times(1) + + taskRef, err := s.CreateVolumeGroup(req) + + assert.Nil(t, err) + assert.Equal(t, "volgroup-abcdef12", taskRef.ResourceID) + assert.Equal(t, "task-abcdef12", taskRef.TaskID) + }) + + t.Run("ConnectionError_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Post("/ecloud/v2/volume-groups", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) + + _, err := s.CreateVolumeGroup(CreateVolumeGroupRequest{}) + + assert.NotNil(t, err) + assert.Equal(t, "test error 1", err.Error()) + }) +} + +func TestPatchVolumeGroup(t *testing.T) { + t.Run("Valid", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + req := PatchVolumeGroupRequest{ + Name: "some volume group", + } + + c.EXPECT().Patch("/ecloud/v2/volume-groups/volgroup-abcdef12", &req).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"task_id\":\"task-abcdef12\"}}"))), + StatusCode: 200, + }, + }, nil).Times(1) + + taskRef, err := s.PatchVolumeGroup("volgroup-abcdef12", req) + + assert.Nil(t, err) + assert.Equal(t, "task-abcdef12", taskRef.TaskID) + }) + + t.Run("ConnectionError_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Patch("/ecloud/v2/volume-groups/volgroup-abcdef12", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) + + _, err := s.PatchVolumeGroup("volgroup-abcdef12", PatchVolumeGroupRequest{}) + + assert.NotNil(t, err) + assert.Equal(t, "test error 1", err.Error()) + }) + + t.Run("InvalidVolumeGroupID_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + _, err := s.PatchVolumeGroup("", PatchVolumeGroupRequest{}) + + assert.NotNil(t, err) + assert.Equal(t, "invalid volume group id", err.Error()) + }) + + t.Run("404_ReturnsVolumeGroupNotFoundError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Patch("/ecloud/v2/volume-groups/volgroup-abcdef12", gomock.Any()).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + StatusCode: 404, + }, + }, nil).Times(1) + + _, err := s.PatchVolumeGroup("volgroup-abcdef12", PatchVolumeGroupRequest{}) + + assert.NotNil(t, err) + assert.IsType(t, &VolumeGroupNotFoundError{}, err) + }) +} + +func TestDeleteVolumeGroup(t *testing.T) { + t.Run("Valid", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Delete("/ecloud/v2/volume-groups/volgroup-abcdef12", nil).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":{\"task_id\":\"task-abcdef12\"}}"))), + StatusCode: 200, + }, + }, nil).Times(1) + + taskID, err := s.DeleteVolumeGroup("volgroup-abcdef12") + + assert.Nil(t, err) + assert.Equal(t, "task-abcdef12", taskID) + }) + + t.Run("ConnectionError_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Delete("/ecloud/v2/volume-groups/volgroup-abcdef12", nil).Return(&connection.APIResponse{}, errors.New("test error 1")).Times(1) + + _, err := s.DeleteVolumeGroup("volgroup-abcdef12") + + assert.NotNil(t, err) + assert.Equal(t, "test error 1", err.Error()) + }) + + t.Run("InvalidVolumeGroupID_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + _, err := s.DeleteVolumeGroup("") + + assert.NotNil(t, err) + assert.Equal(t, "invalid volume group id", err.Error()) + }) + + t.Run("404_ReturnsVolumeGroupNotFoundError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Delete("/ecloud/v2/volume-groups/volgroup-abcdef12", nil).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + StatusCode: 404, + }, + }, nil).Times(1) + + _, err := s.DeleteVolumeGroup("volgroup-abcdef12") + + assert.NotNil(t, err) + assert.IsType(t, &VolumeGroupNotFoundError{}, err) + }) +} + +func TestGetVolumeGroupTasks(t *testing.T) { + t.Run("Single", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12/tasks", gomock.Any()).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":[{\"id\":\"task-abcdef12\"}],\"meta\":{\"pagination\":{\"total_pages\":1}}}"))), + StatusCode: 200, + }, + }, nil).Times(1) + + tasks, err := s.GetVolumeGroupTasks("volgroup-abcdef12", connection.APIRequestParameters{}) + + assert.Nil(t, err) + assert.Len(t, tasks, 1) + assert.Equal(t, "task-abcdef12", tasks[0].ID) + }) + + t.Run("ConnectionError_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12/tasks", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")) + + _, err := s.GetVolumeGroupTasks("volgroup-abcdef12", connection.APIRequestParameters{}) + + assert.NotNil(t, err) + assert.Equal(t, "test error 1", err.Error()) + }) + + t.Run("InvalidVolumeGroupID_ReturnsError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + _, err := s.GetVolumeGroupTasks("", connection.APIRequestParameters{}) + + assert.NotNil(t, err) + assert.Equal(t, "invalid volume group id", err.Error()) + }) + + t.Run("404_ReturnsRouterNotFoundError", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + c := mocks.NewMockConnection(mockCtrl) + + s := Service{ + connection: c, + } + + c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12/tasks", gomock.Any()).Return(&connection.APIResponse{ + Response: &http.Response{ + Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), + StatusCode: 404, + }, + }, nil).Times(1) + + _, err := s.GetVolumeGroupTasks("volgroup-abcdef12", connection.APIRequestParameters{}) + + assert.NotNil(t, err) + assert.IsType(t, &VolumeGroupNotFoundError{}, err) + }) +} From a3ba4bd45eb6d1942e668353f28a8e5da32d2b22 Mon Sep 17 00:00:00 2001 From: Lee Farrell Date: Wed, 22 Sep 2021 16:32:15 +0100 Subject: [PATCH 2/2] update volume group operations --- pkg/service/ecloud/service.go | 2 ++ pkg/service/ecloud/service_volumegroup.go | 30 +++++++++---------- .../ecloud/service_volumegroup_test.go | 24 +++++++-------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/pkg/service/ecloud/service.go b/pkg/service/ecloud/service.go index 8c3c123..513bb04 100644 --- a/pkg/service/ecloud/service.go +++ b/pkg/service/ecloud/service.go @@ -351,6 +351,8 @@ type ECloudService interface { CreateVolumeGroup(req CreateVolumeGroupRequest) (TaskReference, error) PatchVolumeGroup(groupID string, patch PatchVolumeGroupRequest) (TaskReference, error) DeleteVolumeGroup(groupID string) (string, error) + GetVolumeGroupVolumes(groupID string, parameters connection.APIRequestParameters) ([]Volume, error) + GetVolumeGroupVolumesPaginated(groupID string, parameters connection.APIRequestParameters) (*PaginatedVolume, error) // VPN Endpoint GetVPNEndpoints(parameters connection.APIRequestParameters) ([]VPNEndpoint, error) diff --git a/pkg/service/ecloud/service_volumegroup.go b/pkg/service/ecloud/service_volumegroup.go index 3c2c0c5..bbac500 100644 --- a/pkg/service/ecloud/service_volumegroup.go +++ b/pkg/service/ecloud/service_volumegroup.go @@ -145,40 +145,40 @@ func (s *Service) deleteVolumeGroupResponseBody(volumeGroupID string) (*GetTaskR }) } -// GetVolumeGroupTasks retrieves a list of VolumeGroup tasks -func (s *Service) GetVolumeGroupTasks(volumeGroupID string, parameters connection.APIRequestParameters) ([]Task, error) { - var tasks []Task +// GetVolumeGroupVolumes retrieves a list of VolumeGroup volumes +func (s *Service) GetVolumeGroupVolumes(volumeGroupID string, parameters connection.APIRequestParameters) ([]Volume, error) { + var volumes []Volume getFunc := func(p connection.APIRequestParameters) (connection.Paginated, error) { - return s.GetVolumeGroupTasksPaginated(volumeGroupID, p) + return s.GetVolumeGroupVolumesPaginated(volumeGroupID, p) } responseFunc := func(response connection.Paginated) { - for _, task := range response.(*PaginatedTask).Items { - tasks = append(tasks, task) + for _, volume := range response.(*PaginatedVolume).Items { + volumes = append(volumes, volume) } } - return tasks, connection.InvokeRequestAll(getFunc, responseFunc, parameters) + return volumes, connection.InvokeRequestAll(getFunc, responseFunc, parameters) } -// GetVolumeGroupTasksPaginated retrieves a paginated list of VolumeGroup tasks -func (s *Service) GetVolumeGroupTasksPaginated(volumeGroupID string, parameters connection.APIRequestParameters) (*PaginatedTask, error) { - body, err := s.getVolumeGroupTasksPaginatedResponseBody(volumeGroupID, parameters) +// GetVolumeGroupVolumesPaginated retrieves a paginated list of VolumeGroup volumes +func (s *Service) GetVolumeGroupVolumesPaginated(volumeGroupID string, parameters connection.APIRequestParameters) (*PaginatedVolume, error) { + body, err := s.getVolumeGroupVolumesPaginatedResponseBody(volumeGroupID, parameters) - return NewPaginatedTask(func(p connection.APIRequestParameters) (connection.Paginated, error) { - return s.GetVolumeGroupTasksPaginated(volumeGroupID, p) + return NewPaginatedVolume(func(p connection.APIRequestParameters) (connection.Paginated, error) { + return s.GetVolumeGroupVolumesPaginated(volumeGroupID, p) }, parameters, body.Metadata.Pagination, body.Data), err } -func (s *Service) getVolumeGroupTasksPaginatedResponseBody(volumeGroupID string, parameters connection.APIRequestParameters) (*GetTaskSliceResponseBody, error) { - body := &GetTaskSliceResponseBody{} +func (s *Service) getVolumeGroupVolumesPaginatedResponseBody(volumeGroupID string, parameters connection.APIRequestParameters) (*GetVolumeSliceResponseBody, error) { + body := &GetVolumeSliceResponseBody{} if volumeGroupID == "" { return body, fmt.Errorf("invalid volume group id") } - response, err := s.connection.Get(fmt.Sprintf("/ecloud/v2/volume-groups/%s/tasks", volumeGroupID), parameters) + response, err := s.connection.Get(fmt.Sprintf("/ecloud/v2/volume-groups/%s/volumes", volumeGroupID), parameters) if err != nil { return body, err } diff --git a/pkg/service/ecloud/service_volumegroup_test.go b/pkg/service/ecloud/service_volumegroup_test.go index ce877bd..3062431 100644 --- a/pkg/service/ecloud/service_volumegroup_test.go +++ b/pkg/service/ecloud/service_volumegroup_test.go @@ -355,7 +355,7 @@ func TestDeleteVolumeGroup(t *testing.T) { }) } -func TestGetVolumeGroupTasks(t *testing.T) { +func TestGetVolumeGroupVolumes(t *testing.T) { t.Run("Single", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -366,18 +366,18 @@ func TestGetVolumeGroupTasks(t *testing.T) { connection: c, } - c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12/tasks", gomock.Any()).Return(&connection.APIResponse{ + c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12/volumes", gomock.Any()).Return(&connection.APIResponse{ Response: &http.Response{ - Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":[{\"id\":\"task-abcdef12\"}],\"meta\":{\"pagination\":{\"total_pages\":1}}}"))), + Body: ioutil.NopCloser(bytes.NewReader([]byte("{\"data\":[{\"id\":\"vol-abcdef12\"}],\"meta\":{\"pagination\":{\"total_pages\":1}}}"))), StatusCode: 200, }, }, nil).Times(1) - tasks, err := s.GetVolumeGroupTasks("volgroup-abcdef12", connection.APIRequestParameters{}) + volumes, err := s.GetVolumeGroupVolumes("volgroup-abcdef12", connection.APIRequestParameters{}) assert.Nil(t, err) - assert.Len(t, tasks, 1) - assert.Equal(t, "task-abcdef12", tasks[0].ID) + assert.Len(t, volumes, 1) + assert.Equal(t, "vol-abcdef12", volumes[0].ID) }) t.Run("ConnectionError_ReturnsError", func(t *testing.T) { @@ -390,9 +390,9 @@ func TestGetVolumeGroupTasks(t *testing.T) { connection: c, } - c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12/tasks", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")) + c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12/volumes", gomock.Any()).Return(&connection.APIResponse{}, errors.New("test error 1")) - _, err := s.GetVolumeGroupTasks("volgroup-abcdef12", connection.APIRequestParameters{}) + _, err := s.GetVolumeGroupVolumes("volgroup-abcdef12", connection.APIRequestParameters{}) assert.NotNil(t, err) assert.Equal(t, "test error 1", err.Error()) @@ -408,13 +408,13 @@ func TestGetVolumeGroupTasks(t *testing.T) { connection: c, } - _, err := s.GetVolumeGroupTasks("", connection.APIRequestParameters{}) + _, err := s.GetVolumeGroupVolumes("", connection.APIRequestParameters{}) assert.NotNil(t, err) assert.Equal(t, "invalid volume group id", err.Error()) }) - t.Run("404_ReturnsRouterNotFoundError", func(t *testing.T) { + t.Run("404_ReturnsVolumeGroupNotFoundError", func(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -424,14 +424,14 @@ func TestGetVolumeGroupTasks(t *testing.T) { connection: c, } - c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12/tasks", gomock.Any()).Return(&connection.APIResponse{ + c.EXPECT().Get("/ecloud/v2/volume-groups/volgroup-abcdef12/volumes", gomock.Any()).Return(&connection.APIResponse{ Response: &http.Response{ Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), StatusCode: 404, }, }, nil).Times(1) - _, err := s.GetVolumeGroupTasks("volgroup-abcdef12", connection.APIRequestParameters{}) + _, err := s.GetVolumeGroupVolumes("volgroup-abcdef12", connection.APIRequestParameters{}) assert.NotNil(t, err) assert.IsType(t, &VolumeGroupNotFoundError{}, err)