restore services expected by terraform provider

This commit is contained in:
Kiara Grouwstra 2022-08-16 00:46:44 +02:00
parent 0646c0fc9d
commit a788107028
7 changed files with 1593 additions and 0 deletions

View File

@ -56,6 +56,9 @@ type Client struct {
Keys KeysService
Regions RegionsService
Sizes SizesService
Snapshots SnapshotsService
Storage StorageService
StorageActions StorageActionsService
Tags TagsService
// Optional function called after every successful request made to the DO APIs
@ -194,6 +197,9 @@ func NewClient(httpClient *http.Client) *Client {
c.Keys = &KeysServiceOp{client: c}
c.Regions = &RegionsServiceOp{client: c}
c.Sizes = &SizesServiceOp{client: c}
c.Snapshots = &SnapshotsServiceOp{client: c}
c.Storage = &StorageServiceOp{client: c}
c.StorageActions = &StorageActionsServiceOp{client: c}
c.Tags = &TagsServiceOp{client: c}
c.headers = make(map[string]string)

138
snapshots.go Normal file
View File

@ -0,0 +1,138 @@
package godo
import (
"context"
"fmt"
"net/http"
)
const snapshotBasePath = "v2/snapshots"
// SnapshotsService is an interface for interfacing with the snapshots
// endpoints of the DigitalOcean API
// See: https://docs.digitalocean.com/reference/api/api-reference/#tag/Snapshots
type SnapshotsService interface {
List(context.Context, *ListOptions) ([]Snapshot, *Response, error)
ListVolume(context.Context, *ListOptions) ([]Snapshot, *Response, error)
ListDroplet(context.Context, *ListOptions) ([]Snapshot, *Response, error)
Get(context.Context, string) (*Snapshot, *Response, error)
Delete(context.Context, string) (*Response, error)
}
// SnapshotsServiceOp handles communication with the snapshot related methods of the
// DigitalOcean API.
type SnapshotsServiceOp struct {
client *Client
}
var _ SnapshotsService = &SnapshotsServiceOp{}
// Snapshot represents a DigitalOcean Snapshot
type Snapshot struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
ResourceID string `json:"resource_id,omitempty"`
ResourceType string `json:"resource_type,omitempty"`
Regions []string `json:"regions,omitempty"`
MinDiskSize int `json:"min_disk_size,omitempty"`
SizeGigaBytes float64 `json:"size_gigabytes,omitempty"`
Created string `json:"created_at,omitempty"`
Tags []string `json:"tags,omitempty"`
}
type snapshotRoot struct {
Snapshot *Snapshot `json:"snapshot"`
}
type snapshotsRoot struct {
Snapshots []Snapshot `json:"snapshots"`
Meta *Meta `json:"meta,omitempty"`
}
type listSnapshotOptions struct {
ResourceType string `url:"resource_type,omitempty"`
}
func (s Snapshot) String() string {
return Stringify(s)
}
// List lists all the snapshots available.
func (s *SnapshotsServiceOp) List(ctx context.Context, opt *ListOptions) ([]Snapshot, *Response, error) {
return s.list(ctx, opt, nil)
}
// ListDroplet lists all the Droplet snapshots.
func (s *SnapshotsServiceOp) ListDroplet(ctx context.Context, opt *ListOptions) ([]Snapshot, *Response, error) {
listOpt := listSnapshotOptions{ResourceType: "droplet"}
return s.list(ctx, opt, &listOpt)
}
// ListVolume lists all the volume snapshots.
func (s *SnapshotsServiceOp) ListVolume(ctx context.Context, opt *ListOptions) ([]Snapshot, *Response, error) {
listOpt := listSnapshotOptions{ResourceType: "volume"}
return s.list(ctx, opt, &listOpt)
}
// Get retrieves a snapshot by id.
func (s *SnapshotsServiceOp) Get(ctx context.Context, snapshotID string) (*Snapshot, *Response, error) {
return s.get(ctx, snapshotID)
}
// Delete an snapshot.
func (s *SnapshotsServiceOp) Delete(ctx context.Context, snapshotID string) (*Response, error) {
path := fmt.Sprintf("%s/%s", snapshotBasePath, snapshotID)
req, err := s.client.NewRequest(ctx, http.MethodDelete, path, nil)
if err != nil {
return nil, err
}
resp, err := s.client.Do(ctx, req, nil)
return resp, err
}
// Helper method for getting an individual snapshot
func (s *SnapshotsServiceOp) get(ctx context.Context, ID string) (*Snapshot, *Response, error) {
path := fmt.Sprintf("%s/%s", snapshotBasePath, ID)
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}
root := new(snapshotRoot)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Snapshot, resp, err
}
// Helper method for listing snapshots
func (s *SnapshotsServiceOp) list(ctx context.Context, opt *ListOptions, listOpt *listSnapshotOptions) ([]Snapshot, *Response, error) {
path := snapshotBasePath
path, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}
path, err = addOptions(path, listOpt)
if err != nil {
return nil, nil, err
}
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}
root := new(snapshotsRoot)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Snapshots, resp, err
}

184
snapshots_test.go Normal file
View File

@ -0,0 +1,184 @@
package godo
import (
"context"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestSnapshots_List(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/v2/snapshots", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, `{"snapshots":[{"id":"1"},{"id":"2", "size_gigabytes": 4.84}]}`)
})
ctx := context.Background()
snapshots, _, err := client.Snapshots.List(ctx, nil)
if err != nil {
t.Errorf("Snapshots.List returned error: %v", err)
}
expected := []Snapshot{{ID: "1"}, {ID: "2", SizeGigaBytes: 4.84}}
if !reflect.DeepEqual(snapshots, expected) {
t.Errorf("Snapshots.List returned %+v, expected %+v", snapshots, expected)
}
}
func TestSnapshots_ListVolume(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/v2/snapshots", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
expected := "volume"
actual := r.URL.Query().Get("resource_type")
if actual != expected {
t.Errorf("'type' query = %v, expected %v", actual, expected)
}
fmt.Fprint(w, `{"snapshots":[{"id":"1"},{"id":"2"}]}`)
})
ctx := context.Background()
snapshots, _, err := client.Snapshots.ListVolume(ctx, nil)
if err != nil {
t.Errorf("Snapshots.ListVolume returned error: %v", err)
}
expected := []Snapshot{{ID: "1"}, {ID: "2"}}
if !reflect.DeepEqual(snapshots, expected) {
t.Errorf("Snapshots.ListVolume returned %+v, expected %+v", snapshots, expected)
}
}
func TestSnapshots_ListDroplet(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/v2/snapshots", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
expected := "droplet"
actual := r.URL.Query().Get("resource_type")
if actual != expected {
t.Errorf("'resource_type' query = %v, expected %v", actual, expected)
}
fmt.Fprint(w, `{"snapshots":[{"id":"1"},{"id":"2", "size_gigabytes": 4.84}]}`)
})
ctx := context.Background()
snapshots, _, err := client.Snapshots.ListDroplet(ctx, nil)
if err != nil {
t.Errorf("Snapshots.ListDroplet returned error: %v", err)
}
expected := []Snapshot{{ID: "1"}, {ID: "2", SizeGigaBytes: 4.84}}
if !reflect.DeepEqual(snapshots, expected) {
t.Errorf("Snapshots.ListDroplet returned %+v, expected %+v", snapshots, expected)
}
}
func TestSnapshots_ListSnapshotsMultiplePages(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/v2/snapshots", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, `{"snapshots": [{"id":"1"},{"id":"2"}], "links":{"pages":{"next":"http://example.com/v2/snapshots/?page=2"}}}`)
})
ctx := context.Background()
_, _, err := client.Snapshots.List(ctx, &ListOptions{Page: 2})
if err != nil {
t.Fatal(err)
}
}
func TestSnapshots_RetrievePageByNumber(t *testing.T) {
setup()
defer teardown()
jBlob := `
{
"snapshots": [{"id":"1"},{"id":"2"}],
"links":{
"pages":{
"next":"http://example.com/v2/snapshots/?page=3",
"prev":"http://example.com/v2/snapshots/?page=1",
"last":"http://example.com/v2/snapshots/?page=3",
"first":"http://example.com/v2/snapshots/?page=1"
}
}
}`
mux.HandleFunc("/v2/snapshots", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, jBlob)
})
ctx := context.Background()
opt := &ListOptions{Page: 2}
_, _, err := client.Snapshots.List(ctx, opt)
if err != nil {
t.Fatal(err)
}
}
func TestSnapshots_GetSnapshotByID(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/v2/snapshots/12345", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, `{"snapshot":{"id":"12345"}}`)
})
ctx := context.Background()
snapshots, _, err := client.Snapshots.Get(ctx, "12345")
if err != nil {
t.Errorf("Snapshot.GetByID returned error: %v", err)
}
expected := &Snapshot{ID: "12345"}
if !reflect.DeepEqual(snapshots, expected) {
t.Errorf("Snapshots.GetByID returned %+v, expected %+v", snapshots, expected)
}
}
func TestSnapshots_Destroy(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/v2/snapshots/12345", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodDelete)
})
ctx := context.Background()
_, err := client.Snapshots.Delete(ctx, "12345")
if err != nil {
t.Errorf("Snapshot.Delete returned error: %v", err)
}
}
func TestSnapshot_String(t *testing.T) {
snapshot := &Snapshot{
ID: "1",
Name: "Snapsh176ot",
ResourceID: "0",
ResourceType: "droplet",
Regions: []string{"one"},
MinDiskSize: 20,
SizeGigaBytes: 4.84,
Created: "2013-11-27T09:24:55Z",
Tags: []string{"one", "two"},
}
stringified := snapshot.String()
expected := `godo.Snapshot{ID:"1", Name:"Snapsh176ot", ResourceID:"0", ResourceType:"droplet", Regions:["one"], MinDiskSize:20, SizeGigaBytes:4.84, Created:"2013-11-27T09:24:55Z", Tags:["one" "two"]}`
if expected != stringified {
t.Errorf("Snapshot.String returned %+v, expected %+v", stringified, expected)
}
}

254
storage.go Normal file
View File

@ -0,0 +1,254 @@
package godo
import (
"context"
"fmt"
"net/http"
"time"
)
const (
storageBasePath = "v2"
storageAllocPath = storageBasePath + "/volumes"
storageSnapPath = storageBasePath + "/snapshots"
)
// StorageService is an interface for interfacing with the storage
// endpoints of the Digital Ocean API.
// See: https://docs.digitalocean.com/reference/api/api-reference/#tag/Block-Storage
type StorageService interface {
ListVolumes(context.Context, *ListVolumeParams) ([]Volume, *Response, error)
GetVolume(context.Context, string) (*Volume, *Response, error)
CreateVolume(context.Context, *VolumeCreateRequest) (*Volume, *Response, error)
DeleteVolume(context.Context, string) (*Response, error)
ListSnapshots(ctx context.Context, volumeID string, opts *ListOptions) ([]Snapshot, *Response, error)
GetSnapshot(context.Context, string) (*Snapshot, *Response, error)
CreateSnapshot(context.Context, *SnapshotCreateRequest) (*Snapshot, *Response, error)
DeleteSnapshot(context.Context, string) (*Response, error)
}
// StorageServiceOp handles communication with the storage volumes related methods of the
// DigitalOcean API.
type StorageServiceOp struct {
client *Client
}
// ListVolumeParams stores the options you can set for a ListVolumeCall
type ListVolumeParams struct {
Region string `json:"region"`
Name string `json:"name"`
ListOptions *ListOptions `json:"list_options,omitempty"`
}
var _ StorageService = &StorageServiceOp{}
// Volume represents a Digital Ocean block store volume.
type Volume struct {
ID string `json:"id"`
Region *Region `json:"region"`
Name string `json:"name"`
SizeGigaBytes int64 `json:"size_gigabytes"`
Description string `json:"description"`
DropletIDs []int `json:"droplet_ids"`
CreatedAt time.Time `json:"created_at"`
FilesystemType string `json:"filesystem_type"`
FilesystemLabel string `json:"filesystem_label"`
Tags []string `json:"tags"`
}
func (f Volume) String() string {
return Stringify(f)
}
// URN returns the volume ID as a valid DO API URN
func (f Volume) URN() string {
return ToURN("Volume", f.ID)
}
type storageVolumesRoot struct {
Volumes []Volume `json:"volumes"`
Meta *Meta `json:"meta"`
}
type storageVolumeRoot struct {
Volume *Volume `json:"volume"`
}
// VolumeCreateRequest represents a request to create a block store
// volume.
type VolumeCreateRequest struct {
Region string `json:"region"`
Name string `json:"name"`
Description string `json:"description"`
SizeGigaBytes int64 `json:"size_gigabytes"`
SnapshotID string `json:"snapshot_id"`
FilesystemType string `json:"filesystem_type"`
FilesystemLabel string `json:"filesystem_label"`
Tags []string `json:"tags"`
}
// ListVolumes lists all storage volumes.
func (svc *StorageServiceOp) ListVolumes(ctx context.Context, params *ListVolumeParams) ([]Volume, *Response, error) {
path := storageAllocPath
if params != nil {
if params.Region != "" && params.Name != "" {
path = fmt.Sprintf("%s?name=%s&region=%s", path, params.Name, params.Region)
} else if params.Region != "" {
path = fmt.Sprintf("%s?region=%s", path, params.Region)
} else if params.Name != "" {
path = fmt.Sprintf("%s?name=%s", path, params.Name)
}
if params.ListOptions != nil {
var err error
path, err = addOptions(path, params.ListOptions)
if err != nil {
return nil, nil, err
}
}
}
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}
root := new(storageVolumesRoot)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
if m := root.Meta; m != nil {
resp.Meta = m
}
return root.Volumes, resp, nil
}
// CreateVolume creates a storage volume. The name must be unique.
func (svc *StorageServiceOp) CreateVolume(ctx context.Context, createRequest *VolumeCreateRequest) (*Volume, *Response, error) {
path := storageAllocPath
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, createRequest)
if err != nil {
return nil, nil, err
}
root := new(storageVolumeRoot)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Volume, resp, nil
}
// GetVolume retrieves an individual storage volume.
func (svc *StorageServiceOp) GetVolume(ctx context.Context, id string) (*Volume, *Response, error) {
path := fmt.Sprintf("%s/%s", storageAllocPath, id)
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}
root := new(storageVolumeRoot)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Volume, resp, nil
}
// DeleteVolume deletes a storage volume.
func (svc *StorageServiceOp) DeleteVolume(ctx context.Context, id string) (*Response, error) {
path := fmt.Sprintf("%s/%s", storageAllocPath, id)
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
if err != nil {
return nil, err
}
return svc.client.Do(ctx, req, nil)
}
// SnapshotCreateRequest represents a request to create a block store
// volume.
type SnapshotCreateRequest struct {
VolumeID string `json:"volume_id"`
Name string `json:"name"`
Description string `json:"description"`
Tags []string `json:"tags"`
}
// ListSnapshots lists all snapshots related to a storage volume.
func (svc *StorageServiceOp) ListSnapshots(ctx context.Context, volumeID string, opt *ListOptions) ([]Snapshot, *Response, error) {
path := fmt.Sprintf("%s/%s/snapshots", storageAllocPath, volumeID)
path, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}
root := new(snapshotsRoot)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
if m := root.Meta; m != nil {
resp.Meta = m
}
return root.Snapshots, resp, nil
}
// CreateSnapshot creates a snapshot of a storage volume.
func (svc *StorageServiceOp) CreateSnapshot(ctx context.Context, createRequest *SnapshotCreateRequest) (*Snapshot, *Response, error) {
path := fmt.Sprintf("%s/%s/snapshots", storageAllocPath, createRequest.VolumeID)
req, err := svc.client.NewRequest(ctx, http.MethodPost, path, createRequest)
if err != nil {
return nil, nil, err
}
root := new(snapshotRoot)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Snapshot, resp, nil
}
// GetSnapshot retrieves an individual snapshot.
func (svc *StorageServiceOp) GetSnapshot(ctx context.Context, id string) (*Snapshot, *Response, error) {
path := fmt.Sprintf("%s/%s", storageSnapPath, id)
req, err := svc.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}
root := new(snapshotRoot)
resp, err := svc.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Snapshot, resp, nil
}
// DeleteSnapshot deletes a snapshot.
func (svc *StorageServiceOp) DeleteSnapshot(ctx context.Context, id string) (*Response, error) {
path := fmt.Sprintf("%s/%s", storageSnapPath, id)
req, err := svc.client.NewRequest(ctx, http.MethodDelete, path, nil)
if err != nil {
return nil, err
}
return svc.client.Do(ctx, req, nil)
}

129
storage_actions.go Normal file
View File

@ -0,0 +1,129 @@
package godo
import (
"context"
"fmt"
"net/http"
)
// StorageActionsService is an interface for interfacing with the
// storage actions endpoints of the Digital Ocean API.
// See: https://docs.digitalocean.com/reference/api/api-reference/#tag/Block-Storage-Actions
type StorageActionsService interface {
Attach(ctx context.Context, volumeID string, dropletID int) (*Action, *Response, error)
DetachByDropletID(ctx context.Context, volumeID string, dropletID int) (*Action, *Response, error)
Get(ctx context.Context, volumeID string, actionID int) (*Action, *Response, error)
List(ctx context.Context, volumeID string, opt *ListOptions) ([]Action, *Response, error)
Resize(ctx context.Context, volumeID string, sizeGigabytes int, regionSlug string) (*Action, *Response, error)
}
// StorageActionsServiceOp handles communication with the storage volumes
// action related methods of the DigitalOcean API.
type StorageActionsServiceOp struct {
client *Client
}
// StorageAttachment represents the attachment of a block storage
// volume to a specific Droplet under the device name.
type StorageAttachment struct {
DropletID int `json:"droplet_id"`
}
// Attach a storage volume to a Droplet.
func (s *StorageActionsServiceOp) Attach(ctx context.Context, volumeID string, dropletID int) (*Action, *Response, error) {
request := &ActionRequest{
"type": "attach",
"droplet_id": dropletID,
}
return s.doAction(ctx, volumeID, request)
}
// DetachByDropletID a storage volume from a Droplet by Droplet ID.
func (s *StorageActionsServiceOp) DetachByDropletID(ctx context.Context, volumeID string, dropletID int) (*Action, *Response, error) {
request := &ActionRequest{
"type": "detach",
"droplet_id": dropletID,
}
return s.doAction(ctx, volumeID, request)
}
// Get an action for a particular storage volume by id.
func (s *StorageActionsServiceOp) Get(ctx context.Context, volumeID string, actionID int) (*Action, *Response, error) {
path := fmt.Sprintf("%s/%d", storageAllocationActionPath(volumeID), actionID)
return s.get(ctx, path)
}
// List the actions for a particular storage volume.
func (s *StorageActionsServiceOp) List(ctx context.Context, volumeID string, opt *ListOptions) ([]Action, *Response, error) {
path := storageAllocationActionPath(volumeID)
path, err := addOptions(path, opt)
if err != nil {
return nil, nil, err
}
return s.list(ctx, path)
}
// Resize a storage volume.
func (s *StorageActionsServiceOp) Resize(ctx context.Context, volumeID string, sizeGigabytes int, regionSlug string) (*Action, *Response, error) {
request := &ActionRequest{
"type": "resize",
"size_gigabytes": sizeGigabytes,
"region": regionSlug,
}
return s.doAction(ctx, volumeID, request)
}
func (s *StorageActionsServiceOp) doAction(ctx context.Context, volumeID string, request *ActionRequest) (*Action, *Response, error) {
path := storageAllocationActionPath(volumeID)
req, err := s.client.NewRequest(ctx, http.MethodPost, path, request)
if err != nil {
return nil, nil, err
}
root := new(actionRoot)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Event, resp, err
}
func (s *StorageActionsServiceOp) get(ctx context.Context, path string) (*Action, *Response, error) {
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}
root := new(actionRoot)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
return root.Event, resp, err
}
func (s *StorageActionsServiceOp) list(ctx context.Context, path string) ([]Action, *Response, error) {
req, err := s.client.NewRequest(ctx, http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}
root := new(actionsRoot)
resp, err := s.client.Do(ctx, req, root)
if err != nil {
return nil, resp, err
}
if m := root.Meta; m != nil {
resp.Meta = m
}
return root.Actions, resp, err
}
func storageAllocationActionPath(volumeID string) string {
return fmt.Sprintf("%s/%s/actions", storageAllocPath, volumeID)
}

163
storage_actions_test.go Normal file
View File

@ -0,0 +1,163 @@
package godo
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestStoragesActions_Attach(t *testing.T) {
setup()
defer teardown()
const (
volumeID = "98d414c6-295e-4e3a-ac58-eb9456c1e1d1"
dropletID = 12345
)
attachRequest := &ActionRequest{
"type": "attach",
"droplet_id": float64(dropletID), // encoding/json decodes numbers as floats
}
mux.HandleFunc("/v2/volumes/"+volumeID+"/actions", func(w http.ResponseWriter, r *http.Request) {
v := new(ActionRequest)
err := json.NewDecoder(r.Body).Decode(v)
if err != nil {
t.Fatalf("decode json: %v", err)
}
testMethod(t, r, http.MethodPost)
if !reflect.DeepEqual(v, attachRequest) {
t.Errorf("want=%#v", attachRequest)
t.Errorf("got=%#v", v)
}
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
})
_, _, err := client.StorageActions.Attach(ctx, volumeID, dropletID)
if err != nil {
t.Errorf("StoragesActions.Attach returned error: %v", err)
}
}
func TestStoragesActions_DetachByDropletID(t *testing.T) {
setup()
defer teardown()
volumeID := "98d414c6-295e-4e3a-ac58-eb9456c1e1d1"
dropletID := 123456
detachByDropletIDRequest := &ActionRequest{
"type": "detach",
"droplet_id": float64(dropletID), // encoding/json decodes numbers as floats
}
mux.HandleFunc("/v2/volumes/"+volumeID+"/actions", func(w http.ResponseWriter, r *http.Request) {
v := new(ActionRequest)
err := json.NewDecoder(r.Body).Decode(v)
if err != nil {
t.Fatalf("decode json: %v", err)
}
testMethod(t, r, http.MethodPost)
if !reflect.DeepEqual(v, detachByDropletIDRequest) {
t.Errorf("want=%#v", detachByDropletIDRequest)
t.Errorf("got=%#v", v)
}
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
})
_, _, err := client.StorageActions.DetachByDropletID(ctx, volumeID, dropletID)
if err != nil {
t.Errorf("StoragesActions.DetachByDropletID returned error: %v", err)
}
}
func TestStorageActions_Get(t *testing.T) {
setup()
defer teardown()
volumeID := "98d414c6-295e-4e3a-ac58-eb9456c1e1d1"
mux.HandleFunc("/v2/volumes/"+volumeID+"/actions/456", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
})
action, _, err := client.StorageActions.Get(ctx, volumeID, 456)
if err != nil {
t.Errorf("StorageActions.Get returned error: %v", err)
}
expected := &Action{Status: "in-progress"}
if !reflect.DeepEqual(action, expected) {
t.Errorf("StorageActions.Get returned %+v, expected %+v", action, expected)
}
}
func TestStorageActions_List(t *testing.T) {
setup()
defer teardown()
volumeID := "98d414c6-295e-4e3a-ac58-eb9456c1e1d1"
mux.HandleFunc("/v2/volumes/"+volumeID+"/actions", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprintf(w, `{
"actions": [
{
"status": "in-progress"
}
],
"meta": {
"total": 1
}
}`)
})
actions, resp, err := client.StorageActions.List(ctx, volumeID, nil)
if err != nil {
t.Errorf("StorageActions.List returned error: %v", err)
}
expectedActions := []Action{{Status: "in-progress"}}
if !reflect.DeepEqual(actions, expectedActions) {
t.Errorf("StorageActions.List returned actions %+v, expected %+v", actions, expectedActions)
}
expectedMeta := &Meta{Total: 1}
if !reflect.DeepEqual(resp.Meta, expectedMeta) {
t.Errorf("StorageActions.List returned meta %+v, expected %+v", resp.Meta, expectedMeta)
}
}
func TestStoragesActions_Resize(t *testing.T) {
setup()
defer teardown()
volumeID := "98d414c6-295e-4e3a-ac58-eb9456c1e1d1"
resizeRequest := &ActionRequest{
"type": "resize",
"size_gigabytes": float64(500),
"region": "nyc1",
}
mux.HandleFunc("/v2/volumes/"+volumeID+"/actions", func(w http.ResponseWriter, r *http.Request) {
v := new(ActionRequest)
err := json.NewDecoder(r.Body).Decode(v)
if err != nil {
t.Fatalf("decode json: %v", err)
}
testMethod(t, r, http.MethodPost)
if !reflect.DeepEqual(v, resizeRequest) {
t.Errorf("want=%#v", resizeRequest)
t.Errorf("got=%#v", v)
}
fmt.Fprintf(w, `{"action":{"status":"in-progress"}}`)
})
_, _, err := client.StorageActions.Resize(ctx, volumeID, 500, "nyc1")
if err != nil {
t.Errorf("StoragesActions.Resize returned error: %v", err)
}
}

719
storage_test.go Normal file
View File

@ -0,0 +1,719 @@
package godo
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
"time"
)
func TestStorageVolumes_ListStorageVolumes(t *testing.T) {
setup()
defer teardown()
jBlob := `
{
"volumes": [
{
"user_id": 42,
"region": {"slug": "nyc3"},
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "my volume",
"description": "my description",
"size_gigabytes": 100,
"droplet_ids": [10],
"created_at": "2002-10-02T15:00:00.05Z",
"filesystem_type": "",
"filesystem_label": "",
"tags": ["tag1", "tag2"]
},
{
"user_id": 42,
"region": {"slug": "nyc3"},
"id": "96d414c6-295e-4e3a-ac59-eb9456c1e1d1",
"name": "my other volume",
"description": "my other description",
"size_gigabytes": 100,
"created_at": "2012-10-03T15:00:01.05Z",
"filesystem_type": "ext4",
"filesystem_label": "my-volume",
"tags": []
}
],
"links": {
"pages": {
"last": "https://api.digitalocean.com/v2/volumes?page=2",
"next": "https://api.digitalocean.com/v2/volumes?page=2"
}
},
"meta": {
"total": 28
}
}`
mux.HandleFunc("/v2/volumes/", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, jBlob)
})
volumes, resp, err := client.Storage.ListVolumes(ctx, nil)
if err != nil {
t.Errorf("Storage.ListVolumes returned error: %v", err)
}
expectedVolume := []Volume{
{
Region: &Region{Slug: "nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "my volume",
Description: "my description",
SizeGigaBytes: 100,
DropletIDs: []int{10},
CreatedAt: time.Date(2002, 10, 02, 15, 00, 00, 50000000, time.UTC),
Tags: []string{"tag1", "tag2"},
},
{
Region: &Region{Slug: "nyc3"},
ID: "96d414c6-295e-4e3a-ac59-eb9456c1e1d1",
Name: "my other volume",
Description: "my other description",
SizeGigaBytes: 100,
CreatedAt: time.Date(2012, 10, 03, 15, 00, 01, 50000000, time.UTC),
FilesystemType: "ext4",
FilesystemLabel: "my-volume",
Tags: []string{},
},
}
if !reflect.DeepEqual(volumes, expectedVolume) {
t.Errorf("Storage.ListVolumes returned volumes %+v, expected %+v", volumes, expectedVolume)
}
expectedMeta := &Meta{
Total: 28,
}
if !reflect.DeepEqual(resp.Meta, expectedMeta) {
t.Errorf("Storage.ListVolumes returned meta %+v, expected %+v", resp.Meta, expectedMeta)
}
}
func TestStorageVolumes_Get(t *testing.T) {
setup()
defer teardown()
want := &Volume{
Region: &Region{Slug: "nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "my volume",
Description: "my description",
SizeGigaBytes: 100,
CreatedAt: time.Date(2002, 10, 02, 15, 00, 00, 50000000, time.UTC),
FilesystemType: "xfs",
FilesystemLabel: "my-vol",
Tags: []string{"tag1", "tag2"},
}
jBlob := `{
"volume":{
"region": {"slug":"nyc3"},
"attached_to_droplet": null,
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "my volume",
"description": "my description",
"size_gigabytes": 100,
"created_at": "2002-10-02T15:00:00.05Z",
"filesystem_type": "xfs",
"filesystem_label": "my-vol",
"tags": ["tag1", "tag2"]
}
}`
mux.HandleFunc("/v2/volumes/80d414c6-295e-4e3a-ac58-eb9456c1e1d1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, jBlob)
})
got, _, err := client.Storage.GetVolume(ctx, "80d414c6-295e-4e3a-ac58-eb9456c1e1d1")
if err != nil {
t.Errorf("Storage.GetVolume returned error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Storage.GetVolume returned %+v, want %+v", got, want)
}
}
func TestStorageVolumes_ListVolumesByName(t *testing.T) {
setup()
defer teardown()
jBlob :=
`{
"volumes": [
{
"region": {"slug": "nyc3"},
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "myvolume",
"description": "my description",
"size_gigabytes": 100,
"droplet_ids": [10],
"created_at": "2002-10-02T15:00:00.05Z",
"filesystem_type": "",
"filesystem_label": "",
"tags": ["tag1", "tag2"]
}
],
"links": {},
"meta": {
"total": 1
}
}`
expectedVolumes := []Volume{
{
Region: &Region{Slug: "nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "myvolume",
Description: "my description",
SizeGigaBytes: 100,
DropletIDs: []int{10},
CreatedAt: time.Date(2002, 10, 02, 15, 00, 00, 50000000, time.UTC),
Tags: []string{"tag1", "tag2"},
},
}
mux.HandleFunc("/v2/volumes", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("name") != "myvolume" || r.URL.Query().Get("region") != "" {
t.Errorf("Storage.ListVolumeByName did not request the correct name or region")
}
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, jBlob)
})
options := &ListVolumeParams{
Name: "myvolume",
}
volumes, resp, err := client.Storage.ListVolumes(ctx, options)
if err != nil {
t.Errorf("Storage.ListVolumeByName returned error: %v", err)
}
if !reflect.DeepEqual(volumes, expectedVolumes) {
t.Errorf("Storage.ListVolumeByName returned volumes %+v, expected %+v", volumes, expectedVolumes)
}
expectedMeta := &Meta{
Total: 1,
}
if !reflect.DeepEqual(resp.Meta, expectedMeta) {
t.Errorf("Storage.ListVolumeByName returned meta %+v, expected %+v", resp.Meta, expectedMeta)
}
}
func TestStorageVolumes_ListVolumesByRegion(t *testing.T) {
setup()
defer teardown()
jBlob :=
`{
"volumes": [
{
"region": {"slug": "nyc3"},
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "myvolume",
"description": "my description",
"size_gigabytes": 100,
"droplet_ids": [10],
"created_at": "2002-10-02T15:00:00.05Z",
"filesystem_type": "",
"filesystem_label": "",
"tags": ["tag1", "tag2"]
}
],
"links": {},
"meta": {
"total": 1
}
}`
expectedVolumes := []Volume{
{
Region: &Region{Slug: "nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "myvolume",
Description: "my description",
SizeGigaBytes: 100,
DropletIDs: []int{10},
CreatedAt: time.Date(2002, 10, 02, 15, 00, 00, 50000000, time.UTC),
Tags: []string{"tag1", "tag2"},
},
}
mux.HandleFunc("/v2/volumes", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("region") != "nyc3" || r.URL.Query().Get("name") != "" {
t.Errorf("Storage.ListVolumeByName did not request the correct name or region")
}
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, jBlob)
})
options := &ListVolumeParams{
Region: "nyc3",
}
volumes, resp, err := client.Storage.ListVolumes(ctx, options)
if err != nil {
t.Errorf("Storage.ListVolumeByName returned error: %v", err)
}
if !reflect.DeepEqual(volumes, expectedVolumes) {
t.Errorf("Storage.ListVolumeByName returned volumes %+v, expected %+v", volumes, expectedVolumes)
}
expectedMeta := &Meta{
Total: 1,
}
if !reflect.DeepEqual(resp.Meta, expectedMeta) {
t.Errorf("Storage.ListVolumeByName returned meta %+v, expected %+v", resp.Meta, expectedMeta)
}
}
func TestStorageVolumes_ListVolumesByNameAndRegion(t *testing.T) {
setup()
defer teardown()
jBlob :=
`{
"volumes": [
{
"region": {"slug": "nyc3"},
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "myvolume",
"description": "my description",
"size_gigabytes": 100,
"droplet_ids": [10],
"created_at": "2002-10-02T15:00:00.05Z",
"filesystem_type": "",
"filesystem_label": "",
"tags": ["tag1", "tag2"]
}
],
"links": {},
"meta": {
"total": 1
}
}`
expectedVolumes := []Volume{
{
Region: &Region{Slug: "nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "myvolume",
Description: "my description",
SizeGigaBytes: 100,
DropletIDs: []int{10},
CreatedAt: time.Date(2002, 10, 02, 15, 00, 00, 50000000, time.UTC),
Tags: []string{"tag1", "tag2"},
},
}
mux.HandleFunc("/v2/volumes", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("region") != "nyc3" || r.URL.Query().Get("name") != "myvolume" {
t.Errorf("Storage.ListVolumeByName did not request the correct name or region")
}
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, jBlob)
})
options := &ListVolumeParams{
Region: "nyc3",
Name: "myvolume",
}
volumes, resp, err := client.Storage.ListVolumes(ctx, options)
if err != nil {
t.Errorf("Storage.ListVolumeByName returned error: %v", err)
}
if !reflect.DeepEqual(volumes, expectedVolumes) {
t.Errorf("Storage.ListVolumeByName returned volumes %+v, expected %+v", volumes, expectedVolumes)
}
expectedMeta := &Meta{
Total: 1,
}
if !reflect.DeepEqual(resp.Meta, expectedMeta) {
t.Errorf("Storage.ListVolumeByName returned meta %+v, expected %+v", resp.Meta, expectedMeta)
}
}
func TestStorageVolumes_Create(t *testing.T) {
setup()
defer teardown()
createRequest := &VolumeCreateRequest{
Region: "nyc3",
Name: "my volume",
Description: "my description",
SizeGigaBytes: 100,
Tags: []string{"tag1", "tag2"},
}
want := &Volume{
Region: &Region{Slug: "nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "my volume",
Description: "my description",
SizeGigaBytes: 100,
CreatedAt: time.Date(2002, 10, 02, 15, 00, 00, 50000000, time.UTC),
Tags: []string{"tag1", "tag2"},
}
jBlob := `{
"volume":{
"region": {"slug":"nyc3"},
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "my volume",
"description": "my description",
"size_gigabytes": 100,
"created_at": "2002-10-02T15:00:00.05Z",
"tags": ["tag1", "tag2"]
},
"links": {}
}`
mux.HandleFunc("/v2/volumes", func(w http.ResponseWriter, r *http.Request) {
v := new(VolumeCreateRequest)
err := json.NewDecoder(r.Body).Decode(v)
if err != nil {
t.Fatal(err)
}
testMethod(t, r, http.MethodPost)
if !reflect.DeepEqual(v, createRequest) {
t.Errorf("Request body = %+v, expected %+v", v, createRequest)
}
fmt.Fprint(w, jBlob)
})
got, _, err := client.Storage.CreateVolume(ctx, createRequest)
if err != nil {
t.Errorf("Storage.CreateVolume returned error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Storage.CreateVolume returned %+v, want %+v", got, want)
}
}
func TestStorageVolumes_CreateFormatted(t *testing.T) {
setup()
defer teardown()
createRequest := &VolumeCreateRequest{
Region: "nyc3",
Name: "my volume",
Description: "my description",
SizeGigaBytes: 100,
FilesystemType: "xfs",
Tags: []string{"tag1", "tag2"},
}
want := &Volume{
Region: &Region{Slug: "nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "my volume",
Description: "my description",
SizeGigaBytes: 100,
CreatedAt: time.Date(2002, 10, 02, 15, 00, 00, 50000000, time.UTC),
FilesystemType: "xfs",
Tags: []string{"tag1", "tag2"},
}
jBlob := `{
"volume":{
"region": {"slug":"nyc3"},
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "my volume",
"description": "my description",
"size_gigabytes": 100,
"created_at": "2002-10-02T15:00:00.05Z",
"filesystem_type": "xfs",
"filesystem_label": "",
"tags": ["tag1", "tag2"]
},
"links": {}
}`
mux.HandleFunc("/v2/volumes", func(w http.ResponseWriter, r *http.Request) {
v := new(VolumeCreateRequest)
err := json.NewDecoder(r.Body).Decode(v)
if err != nil {
t.Fatal(err)
}
testMethod(t, r, http.MethodPost)
if !reflect.DeepEqual(v, createRequest) {
t.Errorf("Request body = %+v, expected %+v", v, createRequest)
}
fmt.Fprint(w, jBlob)
})
got, _, err := client.Storage.CreateVolume(ctx, createRequest)
if err != nil {
t.Errorf("Storage.CreateVolume returned error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Storage.CreateVolume returned %+v, want %+v", got, want)
}
}
func TestStorageVolumes_CreateFromSnapshot(t *testing.T) {
setup()
defer teardown()
createRequest := &VolumeCreateRequest{
Name: "my-volume-from-a-snapshot",
Description: "my description",
SizeGigaBytes: 100,
SnapshotID: "0d165eff-0b4c-11e7-9093-0242ac110207",
Tags: []string{"tag1", "tag2"},
}
want := &Volume{
Region: &Region{Slug: "nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "my-volume-from-a-snapshot",
Description: "my description",
SizeGigaBytes: 100,
CreatedAt: time.Date(2002, 10, 02, 15, 00, 00, 50000000, time.UTC),
Tags: []string{"tag1", "tag2"},
}
jBlob := `{
"volume":{
"region": {"slug":"nyc3"},
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "my-volume-from-a-snapshot",
"description": "my description",
"size_gigabytes": 100,
"created_at": "2002-10-02T15:00:00.05Z",
"tags": ["tag1", "tag2"]
},
"links": {}
}`
mux.HandleFunc("/v2/volumes", func(w http.ResponseWriter, r *http.Request) {
v := new(VolumeCreateRequest)
err := json.NewDecoder(r.Body).Decode(v)
if err != nil {
t.Fatal(err)
}
testMethod(t, r, http.MethodPost)
if !reflect.DeepEqual(v, createRequest) {
t.Errorf("Request body = %+v, expected %+v", v, createRequest)
}
fmt.Fprint(w, jBlob)
})
got, _, err := client.Storage.CreateVolume(ctx, createRequest)
if err != nil {
t.Errorf("Storage.CreateVolume returned error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Storage.CreateVolume returned %+v, want %+v", got, want)
}
}
func TestStorageVolumes_Destroy(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/v2/volumes/80d414c6-295e-4e3a-ac58-eb9456c1e1d1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodDelete)
})
_, err := client.Storage.DeleteVolume(ctx, "80d414c6-295e-4e3a-ac58-eb9456c1e1d1")
if err != nil {
t.Errorf("Storage.DeleteVolume returned error: %v", err)
}
}
func TestStorageSnapshots_ListStorageSnapshots(t *testing.T) {
setup()
defer teardown()
jBlob := `
{
"snapshots": [
{
"regions": ["nyc3"],
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "my snapshot",
"size_gigabytes": 100,
"created_at": "2002-10-02T15:00:00.05Z"
},
{
"regions": ["nyc3"],
"id": "96d414c6-295e-4e3a-ac59-eb9456c1e1d1",
"name": "my other snapshot",
"size_gigabytes": 100,
"created_at": "2012-10-03T15:00:01.05Z"
}
],
"links": {
"pages": {
"last": "https://api.digitalocean.com/v2/volumes?page=2",
"next": "https://api.digitalocean.com/v2/volumes?page=2"
}
},
"meta": {
"total": 28
}
}`
mux.HandleFunc("/v2/volumes/98d414c6-295e-4e3a-ac58-eb9456c1e1d1/snapshots", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, jBlob)
})
volumes, resp, err := client.Storage.ListSnapshots(ctx, "98d414c6-295e-4e3a-ac58-eb9456c1e1d1", nil)
if err != nil {
t.Errorf("Storage.ListSnapshots returned error: %v", err)
}
expectedSnapshots := []Snapshot{
{
Regions: []string{"nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "my snapshot",
SizeGigaBytes: 100,
Created: "2002-10-02T15:00:00.05Z",
},
{
Regions: []string{"nyc3"},
ID: "96d414c6-295e-4e3a-ac59-eb9456c1e1d1",
Name: "my other snapshot",
SizeGigaBytes: 100,
Created: "2012-10-03T15:00:01.05Z",
},
}
if !reflect.DeepEqual(volumes, expectedSnapshots) {
t.Errorf("Storage.ListSnapshots returned snapshots %+v, expected %+v", volumes, expectedSnapshots)
}
expectedMeta := &Meta{
Total: 28,
}
if !reflect.DeepEqual(resp.Meta, expectedMeta) {
t.Errorf("Storage.ListSnapshots returned meta %+v, expected %+v", resp.Meta, expectedMeta)
}
}
func TestStorageSnapshots_Get(t *testing.T) {
setup()
defer teardown()
want := &Snapshot{
Regions: []string{"nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "my snapshot",
SizeGigaBytes: 100,
Created: "2002-10-02T15:00:00.05Z",
}
jBlob := `{
"snapshot":{
"regions": ["nyc3"],
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "my snapshot",
"size_gigabytes": 100,
"created_at": "2002-10-02T15:00:00.05Z"
}
}`
mux.HandleFunc("/v2/snapshots/80d414c6-295e-4e3a-ac58-eb9456c1e1d1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)
fmt.Fprint(w, jBlob)
})
got, _, err := client.Storage.GetSnapshot(ctx, "80d414c6-295e-4e3a-ac58-eb9456c1e1d1")
if err != nil {
t.Errorf("Storage.GetSnapshot returned error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Storage.GetSnapshot returned %+v, want %+v", got, want)
}
}
func TestStorageSnapshots_Create(t *testing.T) {
setup()
defer teardown()
createRequest := &SnapshotCreateRequest{
VolumeID: "98d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "my snapshot",
Description: "my description",
Tags: []string{"one", "two"},
}
want := &Snapshot{
Regions: []string{"nyc3"},
ID: "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
Name: "my snapshot",
SizeGigaBytes: 100,
Created: "2002-10-02T15:00:00.05Z",
Tags: []string{"one", "two"},
}
jBlob := `{
"snapshot":{
"regions": ["nyc3"],
"id": "80d414c6-295e-4e3a-ac58-eb9456c1e1d1",
"name": "my snapshot",
"description": "my description",
"size_gigabytes": 100,
"created_at": "2002-10-02T15:00:00.05Z",
"tags": ["one", "two"]
},
"links": {
"pages": {
"last": "https://api.digitalocean.com/v2/volumes/98d414c6-295e-4e3a-ac58-eb9456c1e1d1/snapshots?page=2",
"next": "https://api.digitalocean.com/v2/volumes/98d414c6-295e-4e3a-ac58-eb9456c1e1d1/snapshots?page=2"
}
},
"meta": {
"total": 28
}
}`
mux.HandleFunc("/v2/volumes/98d414c6-295e-4e3a-ac58-eb9456c1e1d1/snapshots", func(w http.ResponseWriter, r *http.Request) {
v := new(SnapshotCreateRequest)
err := json.NewDecoder(r.Body).Decode(v)
if err != nil {
t.Fatal(err)
}
testMethod(t, r, http.MethodPost)
if !reflect.DeepEqual(v, createRequest) {
t.Errorf("Request body = %+v, expected %+v", v, createRequest)
}
fmt.Fprint(w, jBlob)
})
got, _, err := client.Storage.CreateSnapshot(ctx, createRequest)
if err != nil {
t.Errorf("Storage.CreateSnapshot returned error: %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("Storage.CreateSnapshot returned %+v, want %+v", got, want)
}
}
func TestStorageSnapshots_Destroy(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/v2/snapshots/80d414c6-295e-4e3a-ac58-eb9456c1e1d1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodDelete)
})
_, err := client.Storage.DeleteSnapshot(ctx, "80d414c6-295e-4e3a-ac58-eb9456c1e1d1")
if err != nil {
t.Errorf("Storage.DeleteSnapshot returned error: %v", err)
}
}