Skip to content

Commit

Permalink
Merge pull request digitalocean#3 from digitaloceancloud/api-interfaces
Browse files Browse the repository at this point in the history
Services are interfaces
  • Loading branch information
bryanl committed Sep 4, 2014
2 parents 81b1242 + 4b5588d commit 6a5163c
Show file tree
Hide file tree
Showing 20 changed files with 242 additions and 84 deletions.
16 changes: 12 additions & 4 deletions action.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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)
Expand All @@ -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 {
Expand Down
35 changes: 23 additions & 12 deletions action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
28 changes: 21 additions & 7 deletions domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
}
Expand All @@ -29,6 +42,7 @@ type DomainRecord struct {
Weight int `json:"weight,omitempty"`
}

// DomainRecordsOptions are options for DomainRecords
type DomainRecordsOptions struct {
ListOptions
}
Expand All @@ -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 {
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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) {
Expand All @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions domains_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
42 changes: 29 additions & 13 deletions droplet_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
Expand All @@ -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,
}
Expand All @@ -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,
}
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand Down
6 changes: 6 additions & 0 deletions droplet_actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading

0 comments on commit 6a5163c

Please sign in to comment.