From 4b5588d8856632965b0f0d3b5fd97a98e7080250 Mon Sep 17 00:00:00 2001 From: bryanl Date: Thu, 4 Sep 2014 15:53:41 -0400 Subject: [PATCH] Services are interfaces * Converted services to interfaces to make testing with them in downstream projects easier to do. * Removed testify dependency. --- action.go | 16 +++++++++---- action_test.go | 35 +++++++++++++++++++---------- domains.go | 28 +++++++++++++++++------ domains_test.go | 6 +++++ droplet_actions.go | 42 ++++++++++++++++++++++++----------- droplet_actions_test.go | 6 +++++ droplets.go | 25 +++++++++++++++------ droplets_test.go | 6 +++++ doapi.go => godo.go | 36 +++++++++++++++--------------- doapi_test.go => godo_test.go | 9 ++++++++ image_actions.go | 16 +++++++++---- image_actions_test.go | 6 +++++ images.go | 13 ++++++++--- images_test.go | 6 +++++ keys.go | 32 +++++++++++++++++--------- keys_test.go | 6 +++++ regions.go | 13 ++++++++--- regions_test.go | 6 +++++ sizes.go | 13 ++++++++--- sizes_test.go | 6 +++++ 20 files changed, 242 insertions(+), 84 deletions(-) rename doapi.go => godo.go (92%) rename doapi_test.go => godo_test.go (97%) diff --git a/action.go b/action.go index dd596da..2e31e1e 100644 --- a/action.go +++ b/action.go @@ -12,9 +12,16 @@ const ( ActionCompleted = "completed" ) -// ImageActionsService handles communition with the image action related methods of the +// ActionsService handles communction with action related methods of the +// DigitalOcean API: https://developers.digitalocean.com/#actions +type ActionsService interface { + List() ([]Action, *Response, error) + Get(int) (*Action, *Response, error) +} + +// ActionsServiceOp handles communition with the image action related methods of the // DigitalOcean API. -type ActionsService struct { +type ActionsServiceOp struct { client *Client } @@ -38,7 +45,7 @@ type Action struct { } // List all actions -func (s *ActionsService) List() ([]Action, *Response, error) { +func (s *ActionsServiceOp) List() ([]Action, *Response, error) { path := actionsBasePath req, err := s.client.NewRequest("GET", path, nil) @@ -55,7 +62,8 @@ func (s *ActionsService) List() ([]Action, *Response, error) { return root.Actions, resp, err } -func (s *ActionsService) Get(id int) (*Action, *Response, error) { +// Get an action by ID +func (s *ActionsServiceOp) Get(id int) (*Action, *Response, error) { path := fmt.Sprintf("%s/%d", actionsBasePath, id) req, err := s.client.NewRequest("GET", path, nil) if err != nil { diff --git a/action_test.go b/action_test.go index 0c116a7..51313a7 100644 --- a/action_test.go +++ b/action_test.go @@ -5,47 +5,58 @@ import ( "net/http" "testing" "time" - - "github.com/stretchr/testify/assert" ) +func TestAction_ActionsServiceOpImplementsActionsService(t *testing.T) { + if !Implements((*ActionsService)(nil), new(ActionsServiceOp)) { + t.Error("ActionsServiceOp does not implement ActionsService") + } +} + func TestAction_List(t *testing.T) { setup() defer teardown() - assert := assert.New(t) - mux.HandleFunc("/v2/actions", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{"actions": [{"id":1},{"id":2}]}`) testMethod(t, r, "GET") }) actions, _, err := client.Actions.List() - assert.NoError(err) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + expected := []Action{{ID: 1}, {ID: 2}} - assert.Equal(expected, actions) + if len(actions) != len(expected) || actions[0].ID != expected[0].ID || actions[1].ID != expected[1].ID { + t.Fatalf("unexpected response") + } } func TestAction_Get(t *testing.T) { setup() defer teardown() - assert := assert.New(t) - mux.HandleFunc("/v2/actions/12345", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{"action": {"id":12345}}`) testMethod(t, r, "GET") }) action, _, err := client.Actions.Get(12345) - assert.NoError(err) - assert.Equal(12345, action.ID) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if action.ID != 12345 { + t.Fatalf("unexpected response") + } } func TestAction_String(t *testing.T) { - assert := assert.New(t) pt, err := time.Parse(time.RFC3339, "2014-05-08T20:36:47Z") - assert.NoError(err) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } startedAt := &Timestamp{ Time: pt, diff --git a/domains.go b/domains.go index d34c298..d9f4042 100644 --- a/domains.go +++ b/domains.go @@ -4,16 +4,29 @@ import "fmt" const domainsBasePath = "v2/domains" -// DomainsService handles communication wit the domain related methods of the +// DomainsService is an interface for managing DNS with the Digital Ocean API. +// See: https://developers.digitalocean.com/#domains and +// https://developers.digitalocean.com/#domain-records +type DomainsService interface { + Records(string, *DomainRecordsOptions) ([]DomainRecord, *Response, error) + Record(string, int) (*DomainRecord, *Response, error) + DeleteRecord(string, int) (*Response, error) + EditRecord(string, int, *DomainRecordEditRequest) (*DomainRecord, *Response, error) + CreateRecord(string, *DomainRecordEditRequest) (*DomainRecord, *Response, error) +} + +// DomainsServiceOp handles communication with the domain related methods of the // DigitalOcean API. -type DomainsService struct { +type DomainsServiceOp struct { client *Client } +// DomainRecordRoot is the root of an individual Domain Record response type DomainRecordRoot struct { DomainRecord *DomainRecord `json:"domain_record"` } +// DomainRecordsRoot is the root of a group of Domain Record responses type DomainRecordsRoot struct { DomainRecords []DomainRecord `json:"domain_records"` } @@ -29,6 +42,7 @@ type DomainRecord struct { Weight int `json:"weight,omitempty"` } +// DomainRecordsOptions are options for DomainRecords type DomainRecordsOptions struct { ListOptions } @@ -54,7 +68,7 @@ func (d DomainRecordEditRequest) String() string { } // Records returns a slice of DomainRecords for a domain -func (s *DomainsService) Records(domain string, opt *DomainRecordsOptions) ([]DomainRecord, *Response, error) { +func (s *DomainsServiceOp) Records(domain string, opt *DomainRecordsOptions) ([]DomainRecord, *Response, error) { path := fmt.Sprintf("%s/%s/records", domainsBasePath, domain) path, err := addOptions(path, opt) if err != nil { @@ -76,7 +90,7 @@ func (s *DomainsService) Records(domain string, opt *DomainRecordsOptions) ([]Do } // Record returns the record id from a domain -func (s *DomainsService) Record(domain string, id int) (*DomainRecord, *Response, error) { +func (s *DomainsServiceOp) Record(domain string, id int) (*DomainRecord, *Response, error) { path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id) req, err := s.client.NewRequest("GET", path, nil) @@ -94,7 +108,7 @@ func (s *DomainsService) Record(domain string, id int) (*DomainRecord, *Response } // DeleteRecord deletes a record from a domain identified by id -func (s *DomainsService) DeleteRecord(domain string, id int) (*Response, error) { +func (s *DomainsServiceOp) DeleteRecord(domain string, id int) (*Response, error) { path := fmt.Sprintf("%s/%s/records/%d", domainsBasePath, domain, id) req, err := s.client.NewRequest("DELETE", path, nil) @@ -108,7 +122,7 @@ func (s *DomainsService) DeleteRecord(domain string, id int) (*Response, error) } // EditRecord edits a record using a DomainRecordEditRequest -func (s *DomainsService) EditRecord( +func (s *DomainsServiceOp) EditRecord( domain string, id int, editRequest *DomainRecordEditRequest) (*DomainRecord, *Response, error) { @@ -129,7 +143,7 @@ func (s *DomainsService) EditRecord( } // CreateRecord creates a record using a DomainRecordEditRequest -func (s *DomainsService) CreateRecord( +func (s *DomainsServiceOp) CreateRecord( domain string, createRequest *DomainRecordEditRequest) (*DomainRecord, *Response, error) { path := fmt.Sprintf("%s/%s/records", domainsBasePath, domain) diff --git a/domains_test.go b/domains_test.go index f7d8348..9e87021 100644 --- a/domains_test.go +++ b/domains_test.go @@ -8,6 +8,12 @@ import ( "testing" ) +func TestAction_DomainsServiceOpImplementsDomainsService(t *testing.T) { + if !Implements((*DomainsService)(nil), new(DomainsServiceOp)) { + t.Error("DomainsServiceOp does not implement DomainsService") + } +} + func TestDomains_AllRecordsForDomainName(t *testing.T) { setup() defer teardown() diff --git a/droplet_actions.go b/droplet_actions.go index ab70577..650257b 100644 --- a/droplet_actions.go +++ b/droplet_actions.go @@ -5,38 +5,54 @@ import ( "net/url" ) -// DropletActionsService handles communication with the droplet action related +// DropletActionsService is an interface for interfacing with the droplet actions +// endpoints of the Digital Ocean API +// See: https://developers.digitalocean.com/#droplet-actions +type DropletActionsService interface { + Shutdown(int) (*Action, *Response, error) + PowerOff(int) (*Action, *Response, error) + PowerCycle(int) (*Action, *Response, error) + Reboot(int) (*Action, *Response, error) + Restore(int, int) (*Action, *Response, error) + Resize(int, string) (*Action, *Response, error) + Rename(int, string) (*Action, *Response, error) + doAction(int, *ActionRequest) (*Action, *Response, error) + Get(int, int) (*Action, *Response, error) + GetByURI(string) (*Action, *Response, error) +} + +// DropletActionsServiceOp handles communication with the droplet action related // methods of the DigitalOcean API. -type DropletActionsService struct { +type DropletActionsServiceOp struct { client *Client } // Shutdown a Droplet -func (s *DropletActionsService) Shutdown(id int) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) Shutdown(id int) (*Action, *Response, error) { request := &ActionRequest{Type: "shutdown"} return s.doAction(id, request) } // PowerOff a Droplet -func (s *DropletActionsService) PowerOff(id int) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) PowerOff(id int) (*Action, *Response, error) { request := &ActionRequest{Type: "power_off"} return s.doAction(id, request) } // PowerCycle a Droplet -func (s *DropletActionsService) PowerCycle(id int) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) PowerCycle(id int) (*Action, *Response, error) { request := &ActionRequest{Type: "power_cycle"} return s.doAction(id, request) } // Reboot a Droplet -func (s *DropletActionsService) Reboot(id int) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) Reboot(id int) (*Action, *Response, error) { request := &ActionRequest{Type: "reboot"} return s.doAction(id, request) } // Restore an image to a Droplet -func (s *DropletActionsService) Restore(id, imageID int) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) Restore(id, imageID int) (*Action, *Response, error) { options := map[string]interface{}{ "image": float64(imageID), } @@ -50,7 +66,7 @@ func (s *DropletActionsService) Restore(id, imageID int) (*Action, *Response, er } // Resize a Droplet -func (s *DropletActionsService) Resize(id int, sizeSlug string) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) Resize(id int, sizeSlug string) (*Action, *Response, error) { options := map[string]interface{}{ "size": sizeSlug, } @@ -64,7 +80,7 @@ func (s *DropletActionsService) Resize(id int, sizeSlug string) (*Action, *Respo } // Rename a Droplet -func (s *DropletActionsService) Rename(id int, name string) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) Rename(id int, name string) (*Action, *Response, error) { options := map[string]interface{}{ "name": name, } @@ -77,7 +93,7 @@ func (s *DropletActionsService) Rename(id int, name string) (*Action, *Response, return s.doAction(id, request) } -func (s *DropletActionsService) doAction(id int, request *ActionRequest) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) doAction(id int, request *ActionRequest) (*Action, *Response, error) { path := dropletActionPath(id) req, err := s.client.NewRequest("POST", path, request) @@ -95,13 +111,13 @@ func (s *DropletActionsService) doAction(id int, request *ActionRequest) (*Actio } // Get an action for a particular droplet by id. -func (s *DropletActionsService) Get(dropletID, actionID int) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) Get(dropletID, actionID int) (*Action, *Response, error) { path := fmt.Sprintf("%s/%d", dropletActionPath(dropletID), actionID) return s.get(path) } // GetByURI gets an action for a particular droplet by id. -func (s *DropletActionsService) GetByURI(rawurl string) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) GetByURI(rawurl string) (*Action, *Response, error) { u, err := url.Parse(rawurl) if err != nil { return nil, nil, err @@ -111,7 +127,7 @@ func (s *DropletActionsService) GetByURI(rawurl string) (*Action, *Response, err } -func (s *DropletActionsService) get(path string) (*Action, *Response, error) { +func (s *DropletActionsServiceOp) get(path string) (*Action, *Response, error) { req, err := s.client.NewRequest("GET", path, nil) if err != nil { return nil, nil, err diff --git a/droplet_actions_test.go b/droplet_actions_test.go index 0a7d2f4..50685e4 100644 --- a/droplet_actions_test.go +++ b/droplet_actions_test.go @@ -8,6 +8,12 @@ import ( "testing" ) +func TestDropletActions_DropletActionsServiceOpImplementsDropletActionsService(t *testing.T) { + if !Implements((*DropletActionsService)(nil), new(DropletActionsServiceOp)) { + t.Error("DropletActionsServiceOp does not implement DropletActionsService") + } +} + func TestDropletActions_Shutdown(t *testing.T) { setup() defer teardown() diff --git a/droplets.go b/droplets.go index 5a68e0a..7049bd9 100644 --- a/droplets.go +++ b/droplets.go @@ -4,9 +4,20 @@ import "fmt" const dropletBasePath = "v2/droplets" -// DropletsService handles communication with the droplet related methods of the +// DropletsService is an interface for interfacing with the droplet +// endpoints of the Digital Ocean API +// See: https://developers.digitalocean.com/#droplets +type DropletsService interface { + List() ([]Droplet, *Response, error) + Get(int) (*DropletRoot, *Response, error) + Create(*DropletCreateRequest) (*DropletRoot, *Response, error) + Delete(int) (*Response, error) + dropletActionStatus(string) (string, error) +} + +// DropletsServiceOp handles communication with the droplet related methods of the // DigitalOcean API. -type DropletsService struct { +type DropletsServiceOp struct { client *Client } @@ -98,7 +109,7 @@ type Link struct { } // List all droplets -func (s *DropletsService) List() ([]Droplet, *Response, error) { +func (s *DropletsServiceOp) List() ([]Droplet, *Response, error) { path := dropletBasePath req, err := s.client.NewRequest("GET", path, nil) @@ -116,7 +127,7 @@ func (s *DropletsService) List() ([]Droplet, *Response, error) { } // Get individual droplet -func (s *DropletsService) Get(dropletID int) (*DropletRoot, *Response, error) { +func (s *DropletsServiceOp) Get(dropletID int) (*DropletRoot, *Response, error) { path := fmt.Sprintf("%s/%d", dropletBasePath, dropletID) req, err := s.client.NewRequest("GET", path, nil) @@ -134,7 +145,7 @@ func (s *DropletsService) Get(dropletID int) (*DropletRoot, *Response, error) { } // Create droplet -func (s *DropletsService) Create(createRequest *DropletCreateRequest) (*DropletRoot, *Response, error) { +func (s *DropletsServiceOp) Create(createRequest *DropletCreateRequest) (*DropletRoot, *Response, error) { path := dropletBasePath req, err := s.client.NewRequest("POST", path, createRequest) @@ -152,7 +163,7 @@ func (s *DropletsService) Create(createRequest *DropletCreateRequest) (*DropletR } // Delete droplet -func (s *DropletsService) Delete(dropletID int) (*Response, error) { +func (s *DropletsServiceOp) Delete(dropletID int) (*Response, error) { path := fmt.Sprintf("%s/%d", dropletBasePath, dropletID) req, err := s.client.NewRequest("DELETE", path, nil) @@ -165,7 +176,7 @@ func (s *DropletsService) Delete(dropletID int) (*Response, error) { return resp, err } -func (s *DropletsService) dropletActionStatus(uri string) (string, error) { +func (s *DropletsServiceOp) dropletActionStatus(uri string) (string, error) { action, _, err := s.client.DropletActions.GetByURI(uri) if err != nil { diff --git a/droplets_test.go b/droplets_test.go index 96e3d2d..2f181ac 100644 --- a/droplets_test.go +++ b/droplets_test.go @@ -8,6 +8,12 @@ import ( "testing" ) +func TestAction_DropletsServiceOpImplementsActionService(t *testing.T) { + if !Implements((*DropletsService)(nil), new(DropletsServiceOp)) { + t.Error("DropletsServiceOp does not implement DropletsService") + } +} + func TestDroplets_ListDroplets(t *testing.T) { setup() defer teardown() diff --git a/doapi.go b/godo.go similarity index 92% rename from doapi.go rename to godo.go index 901026d..1121ab2 100644 --- a/doapi.go +++ b/godo.go @@ -43,15 +43,15 @@ type Client struct { Rate Rate // Services used for communicating with the API - Actions *ActionsService - Domains *DomainsService - Droplet *DropletsService - DropletActions *DropletActionsService - Images *ImagesService - ImageActions *ImageActionsService - Keys *KeysService - Regions *RegionsService - Sizes *SizesService + Actions ActionsService + Domains DomainsService + Droplet DropletsService + DropletActions DropletActionsService + Images ImagesService + ImageActions ImageActionsService + Keys KeysService + Regions RegionsService + Sizes SizesService } // ListOptions specifies the optional parameters to various List methods that @@ -135,15 +135,15 @@ func NewClient(httpClient *http.Client) *Client { baseURL, _ := url.Parse(defaultBaseURL) c := &Client{client: httpClient, BaseURL: baseURL, UserAgent: userAgent} - c.Actions = &ActionsService{client: c} - c.Domains = &DomainsService{client: c} - c.Droplet = &DropletsService{client: c} - c.DropletActions = &DropletActionsService{client: c} - c.Images = &ImagesService{client: c} - c.ImageActions = &ImageActionsService{client: c} - c.Keys = &KeysService{client: c} - c.Regions = &RegionsService{client: c} - c.Sizes = &SizesService{client: c} + c.Actions = &ActionsServiceOp{client: c} + c.Domains = &DomainsServiceOp{client: c} + c.Droplet = &DropletsServiceOp{client: c} + c.DropletActions = &DropletActionsServiceOp{client: c} + c.Images = &ImagesServiceOp{client: c} + c.ImageActions = &ImageActionsServiceOp{client: c} + c.Keys = &KeysServiceOp{client: c} + c.Regions = &RegionsServiceOp{client: c} + c.Sizes = &SizesServiceOp{client: c} return c } diff --git a/doapi_test.go b/godo_test.go similarity index 97% rename from doapi_test.go rename to godo_test.go index 309dea4..cfce6d7 100644 --- a/doapi_test.go +++ b/godo_test.go @@ -367,3 +367,12 @@ func TestResponse_populatePageValues_invalid(t *testing.T) { }, } } + +func Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { + interfaceType := reflect.TypeOf(interfaceObject).Elem() + if !reflect.TypeOf(object).Implements(interfaceType) { + return false + } + + return true +} diff --git a/image_actions.go b/image_actions.go index 5138b77..c1467d7 100644 --- a/image_actions.go +++ b/image_actions.go @@ -2,14 +2,22 @@ package godo import "fmt" -// ImageActionsService handles communition with the image action related methods of the +// ImageActionsService is an interface for interfacing with the image actions +// endpoints of the Digital Ocean API +// See: https://developers.digitalocean.com/#image-actions +type ImageActionsService interface { + Get(int, int) (*Action, *Response, error) + Transfer(int, *ActionRequest) (*Action, *Response, error) +} + +// ImageActionsServiceOp handles communition with the image action related methods of the // DigitalOcean API. -type ImageActionsService struct { +type ImageActionsServiceOp struct { client *Client } // Transfer an image -func (i *ImageActionsService) Transfer(imageID int, transferRequest *ActionRequest) (*Action, *Response, error) { +func (i *ImageActionsServiceOp) Transfer(imageID int, transferRequest *ActionRequest) (*Action, *Response, error) { path := fmt.Sprintf("v2/images/%d/actions", imageID) req, err := i.client.NewRequest("POST", path, transferRequest) @@ -27,7 +35,7 @@ func (i *ImageActionsService) Transfer(imageID int, transferRequest *ActionReque } // Get an action for a particular image by id. -func (i *ImageActionsService) Get(imageID, actionID int) (*Action, *Response, error) { +func (i *ImageActionsServiceOp) Get(imageID, actionID int) (*Action, *Response, error) { path := fmt.Sprintf("v2/images/%d/actions/%d", imageID, actionID) req, err := i.client.NewRequest("GET", path, nil) diff --git a/image_actions_test.go b/image_actions_test.go index fbac998..4f7c7e3 100644 --- a/image_actions_test.go +++ b/image_actions_test.go @@ -8,6 +8,12 @@ import ( "testing" ) +func TestImageActions_ImageActionsServiceOpImplementsImageActionsService(t *testing.T) { + if !Implements((*ImageActionsService)(nil), new(ImageActionsServiceOp)) { + t.Error("ImageActionsServiceOp does not implement ImageActionsService") + } +} + func TestImageActions_Transfer(t *testing.T) { setup() defer teardown() diff --git a/images.go b/images.go index 8551585..35ce2df 100644 --- a/images.go +++ b/images.go @@ -1,8 +1,15 @@ package godo -// ImagesService handles communication with the image related methods of the +// ImagesService is an interface for interfacing with the images +// endpoints of the Digital Ocean API +// See: https://developers.digitalocean.com/#images +type ImagesService interface { + List() ([]Image, *Response, error) +} + +// ImagesServiceOp handles communication with the image related methods of the // DigitalOcean API. -type ImagesService struct { +type ImagesServiceOp struct { client *Client } @@ -29,7 +36,7 @@ func (i Image) String() string { } // List all sizes -func (s *ImagesService) List() ([]Image, *Response, error) { +func (s *ImagesServiceOp) List() ([]Image, *Response, error) { path := "v2/images" req, err := s.client.NewRequest("GET", path, nil) diff --git a/images_test.go b/images_test.go index 03e9af7..83f2081 100644 --- a/images_test.go +++ b/images_test.go @@ -7,6 +7,12 @@ import ( "testing" ) +func TestImages_ImagesServiceOpImplementsImagesService(t *testing.T) { + if !Implements((*ImagesService)(nil), new(ImagesServiceOp)) { + t.Error("ImagesServiceOp does not implement ImagesService") + } +} + func TestImages_List(t *testing.T) { setup() defer teardown() diff --git a/keys.go b/keys.go index 532ea0b..31d980e 100644 --- a/keys.go +++ b/keys.go @@ -4,9 +4,21 @@ import "fmt" const keysBasePath = "v2/account/keys" -// KeysService handles communication with key related method of the +// KeysService is an interface for interfacing with the keys +// endpoints of the Digital Ocean API +// See: https://developers.digitalocean.com/#keys +type KeysService interface { + List() ([]Key, *Response, error) + GetByID(int) (*Key, *Response, error) + GetByFingerprint(string) (*Key, *Response, error) + Create(*KeyCreateRequest) (*Key, *Response, error) + DeleteByID(int) (*Response, error) + DeleteByFingerprint(string) (*Response, error) +} + +// KeysServiceOp handles communication with key related method of the // DigitalOcean API. -type KeysService struct { +type KeysServiceOp struct { client *Client } @@ -37,7 +49,7 @@ type KeyCreateRequest struct { } // List all keys -func (s *KeysService) List() ([]Key, *Response, error) { +func (s *KeysServiceOp) List() ([]Key, *Response, error) { req, err := s.client.NewRequest("GET", keysBasePath, nil) if err != nil { return nil, nil, err @@ -53,7 +65,7 @@ func (s *KeysService) List() ([]Key, *Response, error) { } // Performs a get given a path -func (s *KeysService) get(path string) (*Key, *Response, error) { +func (s *KeysServiceOp) get(path string) (*Key, *Response, error) { req, err := s.client.NewRequest("GET", path, nil) if err != nil { return nil, nil, err @@ -69,19 +81,19 @@ func (s *KeysService) get(path string) (*Key, *Response, error) { } // GetByID gets a Key by id -func (s *KeysService) GetByID(keyID int) (*Key, *Response, error) { +func (s *KeysServiceOp) GetByID(keyID int) (*Key, *Response, error) { path := fmt.Sprintf("%s/%d", keysBasePath, keyID) return s.get(path) } // GetByFingerprint gets a Key by by fingerprint -func (s *KeysService) GetByFingerprint(fingerprint string) (*Key, *Response, error) { +func (s *KeysServiceOp) GetByFingerprint(fingerprint string) (*Key, *Response, error) { path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint) return s.get(path) } // Create a key using a KeyCreateRequest -func (s *KeysService) Create(createRequest *KeyCreateRequest) (*Key, *Response, error) { +func (s *KeysServiceOp) Create(createRequest *KeyCreateRequest) (*Key, *Response, error) { req, err := s.client.NewRequest("POST", keysBasePath, createRequest) if err != nil { return nil, nil, err @@ -97,7 +109,7 @@ func (s *KeysService) Create(createRequest *KeyCreateRequest) (*Key, *Response, } // Delete key using a path -func (s *KeysService) delete(path string) (*Response, error) { +func (s *KeysServiceOp) delete(path string) (*Response, error) { req, err := s.client.NewRequest("DELETE", path, nil) if err != nil { return nil, err @@ -109,13 +121,13 @@ func (s *KeysService) delete(path string) (*Response, error) { } // DeleteByID deletes a key by its id -func (s *KeysService) DeleteByID(keyID int) (*Response, error) { +func (s *KeysServiceOp) DeleteByID(keyID int) (*Response, error) { path := fmt.Sprintf("%s/%d", keysBasePath, keyID) return s.delete(path) } // DeleteByFingerprint deletes a key by its fingerprint -func (s *KeysService) DeleteByFingerprint(fingerprint string) (*Response, error) { +func (s *KeysServiceOp) DeleteByFingerprint(fingerprint string) (*Response, error) { path := fmt.Sprintf("%s/%s", keysBasePath, fingerprint) return s.delete(path) } diff --git a/keys_test.go b/keys_test.go index 4c16287..9645a8f 100644 --- a/keys_test.go +++ b/keys_test.go @@ -8,6 +8,12 @@ import ( "testing" ) +func TestKeys_KeysServiceOpImplementsKeysService(t *testing.T) { + if !Implements((*KeysService)(nil), new(KeysServiceOp)) { + t.Error("KeysServiceOp does not implement KeysService") + } +} + func TestKeys_List(t *testing.T) { setup() defer teardown() diff --git a/regions.go b/regions.go index d8fba0e..f31c3a9 100644 --- a/regions.go +++ b/regions.go @@ -1,8 +1,15 @@ package godo -// RegionsService handles communication with the region related methods of the +// RegionsService is an interface for interfacing with the regions +// endpoints of the Digital Ocean API +// See: https://developers.digitalocean.com/#regions +type RegionsService interface { + List() ([]Region, *Response, error) +} + +// RegionsServiceOp handles communication with the region related methods of the // DigitalOcean API. -type RegionsService struct { +type RegionsServiceOp struct { client *Client } @@ -27,7 +34,7 @@ func (r Region) String() string { } // List all regions -func (s *RegionsService) List() ([]Region, *Response, error) { +func (s *RegionsServiceOp) List() ([]Region, *Response, error) { path := "v2/regions" req, err := s.client.NewRequest("GET", path, nil) diff --git a/regions_test.go b/regions_test.go index 6661324..c94e57d 100644 --- a/regions_test.go +++ b/regions_test.go @@ -7,6 +7,12 @@ import ( "testing" ) +func TestRegions_RegionsServiceOpImplementsRegionsService(t *testing.T) { + if !Implements((*RegionsService)(nil), new(RegionsServiceOp)) { + t.Error("RegionsServiceOp does not implement RegionsService") + } +} + func TestRegions_List(t *testing.T) { setup() defer teardown() diff --git a/sizes.go b/sizes.go index 3fb4bdb..4f3cb8c 100644 --- a/sizes.go +++ b/sizes.go @@ -1,8 +1,15 @@ package godo -// SizesService handles communication with the size related methods of the +// SizesService is an interface for interfacing with the size +// endpoints of the Digital Ocean API +// See: https://developers.digitalocean.com/#sizes +type SizesService interface { + List() ([]Size, *Response, error) +} + +// SizesServiceOp handles communication with the size related methods of the // DigitalOcean API. -type SizesService struct { +type SizesServiceOp struct { client *Client } @@ -26,7 +33,7 @@ type sizesRoot struct { } // List all images -func (s *SizesService) List() ([]Size, *Response, error) { +func (s *SizesServiceOp) List() ([]Size, *Response, error) { path := "v2/sizes" req, err := s.client.NewRequest("GET", path, nil) diff --git a/sizes_test.go b/sizes_test.go index ca95222..4ad59ed 100644 --- a/sizes_test.go +++ b/sizes_test.go @@ -7,6 +7,12 @@ import ( "testing" ) +func TestSizes_SizesServiceOpImplementsSizesService(t *testing.T) { + if !Implements((*SizesService)(nil), new(SizesServiceOp)) { + t.Error("SizesServiceOp does not implement SizesService") + } +} + func TestSizes_List(t *testing.T) { setup() defer teardown()